Livello API: 19
Android 4.4 (KITKAT
) è una nuova release per la piattaforma Android che offre nuove funzionalità per utenti e sviluppatori di app. Questo documento fornisce un'introduzione alle nuove API più importanti.
In qualità di sviluppatore di app, devi scaricare l'immagine di sistema Android 4.4 e la piattaforma SDK da SDK Manager il prima possibile. Se non hai un dispositivo con Android 4.4 su cui testare la tua app, utilizza l'immagine di sistema Android 4.4 per testarla nell'emulatore Android. Dopodiché crea le tue app per la piattaforma Android 4.4 per iniziare a utilizzare le API più recenti.
Aggiorna il livello API target
Per ottimizzare meglio la tua app per i dispositivi con Android 4.4,
devi impostare targetSdkVersion
su
"19"
, installarla su un'immagine di sistema Android 4.4,
testarla e poi pubblicare un aggiornamento con questa modifica.
Puoi utilizzare le API in Android 4.4 e supportare contemporaneamente le versioni precedenti aggiungendo al codice condizioni che controllano il livello dell'API di sistema prima di eseguire le API non supportate dal tuo minSdkVersion
.
Per scoprire di più sul mantenimento della compatibilità con le versioni precedenti, leggi l'articolo Supportare diverse versioni della piattaforma.
Per saperne di più sul funzionamento dei livelli API, leggi l'articolo Che cos'è il livello API?
Modifiche importanti al comportamento
Se hai già pubblicato un'app per Android, tieni presente che la tua app potrebbe essere interessata dalle modifiche in Android 4.4.
Se la tua app legge da uno spazio di archiviazione esterno…
L'app non può leggere i file condivisi sullo spazio di archiviazione esterno quando viene eseguita su Android 4.4, a meno che non disponga dell'autorizzazione READ_EXTERNAL_STORAGE
. In altre parole, i file all'interno della directory restituita da getExternalStoragePublicDirectory()
non sono più accessibili senza l'autorizzazione. Tuttavia, se devi accedere solo alle directory specifiche per la tua app, fornite da getExternalFilesDir()
, non hai bisogno dell'autorizzazione READ_EXTERNAL_STORAGE
.
Se la tua app utilizza WebView…
La tua app potrebbe comportarsi in modo diverso quando viene eseguita su Android 4.4, in particolare quando aggiorni targetSdkVersion
dell'app a "19" o versioni successive.
Il codice alla base della classe WebView
e delle API correlate è stato sottoposto ad upgrade in modo da basarsi su uno snapshot moderno del codice sorgente di Chromium. Ciò comporta una serie di miglioramenti per le prestazioni, il supporto di nuove funzionalità HTML5 e il supporto del debug remoto dei contenuti WebView
. L'ambito di questo upgrade significa che, se la tua app utilizza WebView
, il suo comportamento potrebbe essere interessato in alcuni casi. Sebbene le modifiche al comportamento note siano documentate e influiscano principalmente sulla tua app solo quando aggiorni il targetSdkVersion
della tua app a "19" o versioni successive, il nuovo WebView
opera in "modalità quirks" per fornire alcune funzionalità precedenti nelle app che hanno come target il livello API 18 e versioni precedenti. È possibile che la tua app dipenda da comportamenti sconosciuti della versione precedente di WebView
.
Pertanto, se la tua app esistente utilizza WebView
, è importante che tu effettui il test su Android 4.4 il prima possibile e consulti la pagina Eseguire la migrazione a WebView in Android 4.4 per informazioni su come la tua app potrebbe essere interessata dall'aggiornamento di targetSdkVersion
a "19" o versioni successive.
Se la tua app utilizza AlarmManager…
Se imposti targetSdkVersion
della tua app su "19" o superiore, gli allarmi creati utilizzando set()
o setRepeating()
non saranno esatti.
Per migliorare l'efficienza energetica, ora Android raggruppa le sveglie di tutte le app che si verificano in orari ragionevolmente simili, in modo che il sistema risvegli il dispositivo una volta anziché più volte per gestire ogni sveglia.
Se la sveglia non è associata a un orario esatto, ma è comunque importante che venga attivata durante un intervallo di tempo specifico (ad esempio tra le 14:00 e le 16:00), puoi utilizzare il nuovo metodo setWindow()
, che accetta un orario "minima " per la sveglia e una"finestra " di tempo successiva all'ora minima entro la quale il sistema deve attivare la sveglia.
Se la sveglia deve essere fissata a un'ora esatta (ad esempio per un promemoria di un evento di calendario), puoi utilizzare il nuovo metodo setExact()
.
Questo comportamento di raggruppamento approssimativo si applica solo alle app aggiornate. Se hai impostato targetSdkVersion
su "18" o meno, le sveglie continueranno a comportarsi come nelle versioni precedenti quando vengono eseguite su Android 4.4.
Se la tua app sincronizza i dati utilizzando ContentResolver…
Se imposti targetSdkVersion
della tua app su "19" o versioni successive, la creazione di una sincronizzazione con addPeriodicSync()
eseguirà le operazioni di sincronizzazione in un intervallo flessibile predefinito di circa il 4% del periodo specificato. Ad esempio, se la frequenza del sondaggio è di 24 ore, l'operazione di sincronizzazione potrebbe avvenire in un periodo di circa un'ora ogni giorno, anziché esattamente alla stessa ora ogni giorno.
Per specificare il tuo intervallo flessibile per le operazioni di sincronizzazione, devi iniziare a utilizzare il nuovo metodo requestSync()
. Per ulteriori dettagli, consulta la sezione seguente sugli adattatori di sincronizzazione.
Questo comportamento dell'intervallo flessibile si applica solo alle app aggiornate. Se hai impostato targetSdkVersion
su "18" o una versione precedente, le richieste di sincronizzazione esistenti continueranno a comportarsi come nelle versioni precedenti quando vengono eseguite su Android 4.4.
Framework di stampa
Android ora include un framework completo che consente agli utenti di stampare qualsiasi documento utilizzando una stampante connessa tramite Wi-Fi, Bluetooth o altri servizi. Il sistema gestisce la transazione tra un'app che vuole stampare un documento e i servizi che inviano i processi di stampa a una stampante. Il framework android.print
fornisce tutte le API necessarie per specificare un documento di stampa e inviarlo al sistema per la stampa. Le API di cui hai effettivamente bisogno per una determinata stampa dipendono dai tuoi contenuti.
Stampa di contenuti generici
Se vuoi stampare i contenuti dell'interfaccia utente come documento, devi prima creare una sottoclasse di PrintDocumentAdapter
. In questa classe devi implementare alcuni metodi di callback, tra cui onLayout()
per stabilire il layout in base alle proprietà di stampa fornite e onWrite()
per serializzare i contenuti stampabili in un ParcelFileDescriptor
.
Per scrivere i contenuti in ParcelFileDescriptor
, devi passare un PDF. Le nuove API PdfDocument
offrono un modo pratico per farlo fornendo un Canvas
da getCanvas()
su cui puoi disegnare i tuoi contenuti stampabili. Poi scrivi PdfDocument
in ParcelFileDescriptor
utilizzando il metodo writeTo()
.
Una volta definita l'implementazione per PrintDocumentAdapter
, puoi eseguire i job di stampa su richiesta dell'utente utilizzando il metodo PrintManager
, print()
, che prende PrintDocumentAdapter
come uno dei suoi argomenti.
Stampa di immagini
Se vuoi stampare solo una foto o un'altra bitmap, le API di assistenza nella libreria di supporto faranno tutto il lavoro per te. Basta creare una nuova istanza di PrintHelper
, impostare la modalità di scala con setScaleMode()
e passare Bitmap
a printBitmap()
. È tutto. La libreria gestisce tutte le interazioni rimanenti con il sistema per inviare la bitmap alla stampante.
Servizi di stampa di edifici
In qualità di OEM di stampanti, puoi utilizzare il framework android.printservice
per fornire l'interoperabilità con le tue stampanti dai dispositivi Android. Puoi creare e distribuire servizi di stampa come APK, che gli utenti possono installare sui propri dispositivi . Un'app di servizio di stampa funziona principalmente come servizio senza testa sottoclassificando la classe PrintService
, che riceve i job di stampa dal sistema e li comunica alle stampanti utilizzando i protocolli appropriati.
Per ulteriori informazioni su come stampare i contenuti dell'app, leggi l'articolo Stampare i contenuti.
Provider di servizi SMS
Il provider di contenuti Telephony
("Provider SMS") consente alle app di leggere e scrivere messaggi SMS ed MMS sul dispositivo. Sono incluse tabelle per i messaggi SMS e MMS ricevuti, in bozza, inviati, in attesa e altro ancora.
A partire da Android 4.4, le impostazioni di sistema consentono agli utenti di selezionare un'"app di messaggistica predefinita". Una volta selezionata, solo l'app per SMS predefinita può scrivere al fornitore di servizi SMS e solo l'app per SMS predefinita riceve la trasmissione SMS_DELIVER_ACTION
quando l'utente riceve un SMS o la trasmissione SMS_DELIVER_ACTION
quando l'utente riceve un MMS.WAP_PUSH_DELIVER_ACTION
L'app per SMS predefinita è responsabile della scrittura dei dettagli per il fornitore di servizi SMS quando riceve o invia un nuovo messaggio.
Le altre app che non sono selezionate come app SMS predefinita possono leggere solo il fornitore SMS, ma possono anche ricevere una notifica quando arriva un nuovo SMS ascoltando la trasmissione SMS_RECEIVED_ACTION
, una trasmissione non interrompibile che può essere inviata a più app. Questa trasmissione è destinata alle app che, pur non essendo selezionate come app SMS predefinita, devono leggere messaggi in entrata speciali, ad esempio per eseguire la verifica del numero di telefono.
Per ulteriori informazioni, leggi il post del blog Preparare le app SMS per KitKat.
Wireless e connettività
Host Card Emulation
Ora le app per Android possono emulare le carte NFC ISO14443-4 (ISO-DEP) che utilizzano APDU per lo scambio di dati (come specificato in ISO7816-4). In questo modo, un dispositivo con tecnologia NFC e Android 4.4 può emulare contemporaneamente più carte NFC e un terminale di pagamento NFC o un altro lettore NFC può avviare una transazione con la carta NFC appropriata in base all'identificatore dell'applicazione (AID).
Se vuoi emulare una carta NFC che utilizza questi protocolli nella tua app, crea un componente di servizio basato sulla classe HostApduService
. Se invece la tua app utilizza un elemento sicuro per l'emulazione della carta, devi creare un servizio basato sulla classe OffHostApduService
, che non sarà direttamente coinvolto nelle transazioni, ma è necessario per registrare gli AID che devono essere gestiti dall'elemento sicuro.
Per ulteriori informazioni, leggi la guida sull'emulazione di carte NFC.
Modalità Lettore NFC
Una nuova modalità di lettore NFC consente a un'attività di limitare tutta l'attività NFC alla lettura solo dei tipi di tag che le interessano quando è in primo piano. Puoi attivare la modalità Lettura per la tua attività con enableReaderMode()
, fornendo un'implementazione di NfcAdapter.ReaderCallback
che riceve un callback quando vengono rilevati nuovi tag.
Questa nuova funzionalità, in combinazione con l'emulazione della carta host, consente ad Android di operare su entrambe le estremità di un'interfaccia di pagamento mobile: un dispositivo funziona come terminale di pagamento (un dispositivo che esegue un'attività in modalità Lettore) e un altro dispositivo funziona come client di pagamento (un dispositivo che emula una carta NFC).
Trasmettitori a infrarossi
Quando esegui l'app su un dispositivo che include un trasmettitore a infrarossi (IR), ora puoi trasmettere segnali IR utilizzando le API ConsumerIrManager
. Per ottenere un'istanza di ConsumerIrManager
, chiama getSystemService()
con CONSUMER_IR_SERVICE
come argomento. Puoi quindi eseguire query sulle frequenze IR supportate del dispositivo con getCarrierFrequencies()
e trasmettere i segnali passando la frequenza e il pattern di segnale desiderati con transmit()
.
Devi sempre controllare innanzitutto se un dispositivo include un trasmettitore a infrarossi chiamando hasIrEmitter()
, ma se la tua app è compatibile solo con i dispositivi che ne hanno uno, devi includere un elemento <uses-feature>
nel manifest per "android.hardware.consumerir"
(FEATURE_CONSUMER_IR
).
Multimediale
Riproduzione adattiva
Il supporto della riproduzione video adattiva è ora disponibile con le API MediaCodec
, che consentono di modificare senza interruzioni la risoluzione durante la riproduzione su un Surface
: puoi fornire i frame di input del decodificatore di una nuova risoluzione e la risoluzione dei buffer di output cambia senza un intervallo significativo.
Puoi attivare la riproduzione adattiva aggiungendo due chiavi a MediaFormat
che specificano la risoluzione massima richiesta dal codec per la tua app: KEY_MAX_WIDTH
e KEY_MAX_HEIGHT
. Dopo averli aggiunti al MediaFormat
, passa il MediaFormat
all'istanza MediaCodec
con configure()
.
Il codec eseguirà la transizione tra risoluzioni uguali o inferiori a questi valori in modo fluido. Il codec potrebbe supportare anche risoluzioni superiori a quelle massime specificate (purché rientrino nei limiti dei profili supportati), ma le transizioni a risoluzioni più elevate potrebbero non essere fluide.
Per modificare la risoluzione durante la decodifica del video H.264, continua ad aggiungere frame alla coda utilizzando MediaCodec.queueInputBuffer(), ma assicurati di fornire i nuovi valori Sequence Parameter Set (SPS) e Picture Parameter Set (PPS) insieme al frame di aggiornamento decodificatore istantaneo (IDR) in un unico buffer.
Tuttavia, prima di tentare di configurare il codec per la riproduzione adattiva, devi verificare che il dispositivo supporti la riproduzione adattiva chiamando isFeatureSupported(String)
con FEATURE_AdaptivePlayback
.
Nota:il supporto della riproduzione adattiva è specifico del fornitore. Alcuni codec potrebbero richiedere più memoria per suggerimenti di risoluzione più grandi. Pertanto, devi impostare i valori massimi della risoluzione in base al materiale di origine che stai decodificando.
Timestamp audio on demand
Per facilitare la sincronizzazione audio-video, la nuova classe AudioTimestamp
fornisce dettagli sulla sequenza temporale di un "frame" specifico in uno stream audio gestito da AudioTrack
. Per ottenere il timestamp più recente disponibile, crea un'istanza di un oggetto AudioTimestamp
e passalo a getTimestamp()
. Se la richiesta del timestamp va a buon fine, l'istanza AudioTrack
viene compilata con una posizione in unità di frame, insieme all'ora stimata in cui il frame è stato presentato o è previsto che venga presentato.
Puoi utilizzare il valore di nanoTime
in AudioTimestamp
(che è monotono) per trovare il frame video associato più vicino rispetto a framePosition
, in modo da poter inserire, duplicare o interpolare i frame video in modo che corrispondano all'audio. In alternativa, puoi determinare il tempo delta tra il valore di nanoTime
e il tempo previsto di un fotogramma video futuro (tenendo conto della frequenza di campionamento) per prevedere quale fotogramma audio è previsto nello stesso momento di un fotogramma video.
Lettore di immagini di superficie
La nuova API ImageReader
ti offre l'accesso diretto ai buffer delle immagini durante il loro rendering in un Surface
. Puoi acquisire un ImageReader
con il metodo statico newInstance()
. Poi chiama getSurface()
per creare un nuovo Surface
e carica i dati delle immagini con un produttore come MediaPlayer
o MediaCodec
. Per ricevere una notifica quando sono disponibili nuove immagini dalla piattaforma, implementa l'interfaccia ImageReader.OnImageAvailableListener
e registrala in setOnImageAvailableListener()
.
Ora, mentre disegni contenuti sul tuo Surface
, il tuo ImageReader.OnImageAvailableListener
riceve una chiamata a onImageAvailable()
ogni volta che è disponibile un nuovo frame dell'immagine, fornendoti il ImageReader
corrispondente. Puoi utilizzare ImageReader
per acquisire i dati immagine del frame come oggetto Image
chiamando acquireLatestImage()
o acquireNextImage()
.
L'oggetto Image
fornisce l'accesso diretto al timestamp, al formato, alle dimensioni e ai dati dei pixel dell'immagine in un ByteBuffer
. Tuttavia, affinché la classe Image
possa interpretare le immagini, queste devono essere formattate in base a uno dei tipi definiti dalle costanti in ImageFormat
o PixelFormat
.
Misurazione di picco e RMS
Ora puoi eseguire query sul picco e sull'RMS dello stream audio corrente da Visualizer
creando una nuova istanza di Visualizer.MeasurementPeakRms
e passandola a getMeasurementPeakRms()
. Quando chiami questo metodo, i valori di picco e RMS del Visualizer.MeasurementPeakRms
specificato vengono impostati sugli ultimi valori misurati.
Potenziatore di volume
LoudnessEnhancer
è una nuova sottoclasse di AudioEffect
che consente di aumentare il volume udibile di MediaPlayer
o AudioTrack
. Questo può essere particolarmente utile in combinazione con il nuovo metodo getMeasurementPeakRms()
sopra menzionato, per aumentare il volume delle tracce audio vocali durante la riproduzione di altri contenuti multimediali.
Telecomandi
Android 4.0 (livello API 14) ha introdotto le API RemoteControlClient
che consentono alle app multimediali di utilizzare gli eventi del controller multimediale da client remoti, come i controlli multimediali nella schermata di blocco. Ora le nuove API RemoteController
ti consentono di creare il tuo telecomando, consentendo la creazione di nuove app e periferiche innovative in grado di controllare la riproduzione di qualsiasi app multimediale integrata con RemoteControlClient
.
Per creare un telecomando, puoi implementare l'interfaccia utente come preferisci, ma per inviare gli eventi dei pulsanti multimediali all'app multimediale dell'utente devi creare un servizio che espanda la classe NotificationListenerService
e implementi l'interfaccia RemoteController.OnClientUpdateListener
. L'utilizzo di NotificationListenerService
come base è importante perché fornisce le limitazioni della privacy appropriate, che richiedono agli utenti di attivare la tua app come ascoltatore di notifiche nelle impostazioni di sicurezza del sistema.
La classe NotificationListenerService
include un paio di metodi astratti che devi implementare, ma se ti interessano solo gli eventi del controller multimediale per la gestione della riproduzione dei contenuti multimediali, puoi lasciare vuota l'implementazione per questi eventi e concentrarti sui metodi RemoteController.OnClientUpdateListener
.
Valutazioni dei controllori remoti
Android 4.4 si basa sulle funzionalità esistenti per i client di controllo remoto (app che ricevono eventi di controllo multimediale con RemoteControlClient
) aggiungendo la possibilità per gli utenti di valutare il brano in riproduzione dal telecomando.
La nuova classe Rating
incapsula le informazioni su una valutazione dell'utente. Una valutazione è definita dallo stile di valutazione (RATING_HEART
, RATING_THUMB_UP_DOWN
, RATING_3_STARS
, RATING_4_STARS
, RATING_5_STARS
o RATING_PERCENTAGE
) e dal valore di valutazione appropriato per lo stile.
Per consentire agli utenti di valutare i tuoi brani da un telecomando:
- Indica che vuoi mostrare all'utente l'interfaccia utente della classificazione (se applicabile) aggiungendo il flag
FLAG_KEY_MEDIA_RATING
insetTransportControlFlags()
. - Chiama
editMetadata()
per recuperare unRemoteControlClient.MetadataEditor
e passalo aRATING_KEY_BY_USER
conaddEditableKey()
. - Specifica lo stile di valutazione chiamando
putObject()
e passandoRATING_KEY_BY_USER
come chiave e uno degli stili di valutazione sopra indicati come valore.
Per ricevere un callback quando l'utente modifica la classificazione dal telecomando, implementa la nuova interfaccia RemoteControlClient.OnMetadataUpdateListener
e passa un'istanza a setMetadataUpdateListener()
. Quando l'utente modifica la valutazione, RemoteControlClient.OnMetadataUpdateListener
riceve una chiamata a onMetadataUpdate()
, passando RATING_KEY_BY_USER
come chiave e un oggetto Rating
come valore.
Sottotitoli codificati
VideoView
ora supporta le tracce dei sottotitoli WebVTT durante la riproduzione di video in HTTP Live Streaming (HLS), mostrando la traccia dei sottotitoli in base alle preferenze per i sottotitoli codificati definite dall'utente nelle impostazioni di sistema.
Puoi anche fornire a VideoView
le tracce dei sottotitoli codificati WebVTT utilizzando il metodo addSubtitleSource()
. Questo metodo accetta un InputStream
che trasporta i dati dei sottotitoli e un oggetto MediaFormat
che specifica il formato per i dati dei sottotitoli, che puoi specificare utilizzando createSubtitleFormat()
. Questi sottotitoli vengono visualizzati anche sopra il video in base alle preferenze dell'utente.
Se non utilizzi VideoView
per visualizzare i contenuti video, devi fare in modo che l'overlay dei sottotitoli corrisponda il più possibile alle preferenze dell'utente per i sottotitoli codificati. Una nuova API CaptioningManager
ti consente di eseguire query sulle preferenze relative ai sottotitoli codificati dell'utente, inclusi gli stili definiti da CaptioningManager.CaptionStyle
, come carattere e colore. Se l'utente modifica alcune preferenze dopo l'avvio del video, devi monitorare le modifiche registrando un'istanza di CaptioningManager.CaptioningChangeListener
per ricevere un callback quando una delle preferenze cambia, quindi aggiornare i sottotitoli se necessario.
Animazione e grafica
Scene e transizioni
Il nuovo framework android.transition
fornisce API che facilitano le animazioni tra diversi stati dell'interfaccia utente. Una funzionalità chiave è la possibilità di definire stati distinti dell'interfaccia utente, noti come "scene", creando un layout separato per ciascuno. Quando vuoi animare da una scena all'altra, esegui una "transizione", che calcola l'animazione necessaria per cambiare il layout dalla scena corrente a quella successiva.
Per passare da una scena all'altra, in genere devi eseguire i seguenti passaggi:
- Specifica il
ViewGroup
contenente i componenti dell'interfaccia utente che vuoi modificare. - Specifica il layout che rappresenta il risultato finale della modifica (la scena successiva).
- Specifica il tipo di transizione che deve animare la modifica del layout.
- Esegui la transizione.
Puoi utilizzare un oggetto Scene
per completare i passaggi 1 e 2. Un Scene
contiene metadati che descrivono le proprietà di un layout necessarie per eseguire una transizione, inclusa la visualizzazione principale e il layout della scena. Puoi creare un Scene
utilizzando un costruttore di classe o il metodo statico getSceneForLayout()
.
Dovrai quindi utilizzare TransitionManager
per completare i passaggi 3 e 4. Un modo è passare Scene
al metodo statico go()
. Viene trovata la vista principale della scena nel layout corrente ed eseguita una transizione nelle viste secondarie per raggiungere il layout definito da Scene
.
In alternativa, non è necessario creare un oggetto Scene
, ma puoi chiamare beginDelayedTransition()
specificando un ViewGroup
contenente le visualizzazioni che vuoi modificare. Poi aggiungi, rimuovi o riconfigura le visualizzazioni target. Dopo che il sistema ha disposto le modifiche necessarie, inizia una transizione per animare tutte le visualizzazioni interessate.
Per un maggiore controllo, puoi definire insiemi di transizioni che devono verificarsi tra scene predefinite utilizzando un file XML nella directory res/transition/
del progetto. All'interno di un elemento <transitionManager>
, specifica uno o più tag <transition>
che specificano ciascuno una scena (un riferimento a un file di layout) e la transizione da applicare quando entri e/o esci da quella scena. Quindi, espandi questo insieme di transizioni utilizzando inflateTransitionManager()
. Utilizza il valore TransitionManager
restituito per eseguire ogni transizione con transitionTo()
, passando un valore Scene
rappresentato da uno dei tag <transition>
. Puoi anche definire in modo programmatico insiemi di transizioni con le API TransitionManager
.
Quando specifichi una transizione, puoi utilizzare diversi tipi predefiniti definiti da sottoclassi di Transition
, ad esempio Fade
e ChangeBounds
. Se non specifichi un tipo di transizione, per impostazione predefinita il sistema utilizza AutoTransition
, che attenua, sposta e ridimensiona automaticamente le visualizzazioni in base alle necessità. Inoltre, puoi creare transizioni personalizzate estendendo una di queste classi per eseguire le animazioni come preferisci. Una transizione personalizzata può monitorare le modifiche alle proprietà che preferisci e creare qualsiasi animazione in base a queste modifiche. Ad esempio, puoi fornire una sottoclasse di Transition
che ascolti le modifiche alla proprietà "rotation" di una vista e poi le animi.
Per ulteriori informazioni, consulta la documentazione di TransitionManager
.
Messa in pausa dell'animatore
Le API Animator
ora ti consentono di mettere in pausa e riprendere un'animazione in corso con i metodi pause()
e resume()
.
Per monitorare lo stato di un'animazione, puoi implementare l'interfaccia Animator.AnimatorPauseListener
, che fornisce i callback quando un'animazione viene messa in pausa e ripristinata: pause()
e resume()
. Aggiungi poi l'ascoltatore a un oggetto Animator
con addPauseListener()
.
In alternativa, puoi creare una sottoclasse della classe astratta AnimatorListenerAdapter
, che ora include implementazioni vuote per i callback di pausa e ripresa definiti da Animator.AnimatorPauseListener
.
Bitmap riutilizzabili
Ora puoi riutilizzare qualsiasi bitmap mutabile in BitmapFactory
per decodificare qualsiasi altra bitmap, anche se la nuova bitmap ha dimensioni diverse, purché il numero di byte risultante della bitmap decodificata (disponibile da getByteCount()
) sia inferiore o uguale al numero di byte allocati della bitmap riutilizzata (disponibile da getAllocationByteCount()
. Per ulteriori informazioni, vedi inBitmap
.
Le nuove API per Bitmap
consentono una riconfigurazione simile per il riutilizzo al di fuori di Bitmap
(per la generazione manuale di bitmap o la logica di decodifica personalizzata).BitmapFactory
Ora puoi impostare le dimensioni di una bitmap con i metodi setHeight()
e setWidth()
e specificare un nuovo Bitmap.Config
con setConfig()
senza influire sull'allocazione della bitmap sottostante. Il metodo reconfigure()
offre anche un modo pratico per combinare queste modifiche con una sola chiamata.
Tuttavia, non devi riconfigurare una bitmap attualmente utilizzata dal sistema di visualizzazione, perché il buffer dei pixel sottostante non verrà rimappato in modo prevedibile.
Contenuti generati dagli utenti
Framework di accesso allo spazio di archiviazione
Nelle versioni precedenti di Android, se vuoi che la tua app recuperi un tipo specifico di file da un'altra app, deve richiamare un'intent con l'azione ACTION_GET_CONTENT
. Questa azione è ancora il modo appropriato per richiedere un file da importare nella tua app. Tuttavia, Android 4.4 introduce l'azione ACTION_OPEN_DOCUMENT
, che consente all'utente di selezionare un file di un tipo specifico e concedere alla tua app l'accesso in lettura a lungo termine a quel file (eventualmente con accesso in scrittura) senza importarlo nella tua app.
Se stai sviluppando un'app che fornisce servizi di archiviazione per i file (ad esempio un servizio di salvataggio sul cloud), puoi utilizzare questa UI unificata per la scelta dei file implementando un provider di contenuti come sottoclasse della nuova classe DocumentsProvider
. La sottoclasse di DocumentsProvider
deve includere un filtro per intent che accetti l'azione PROVIDER_INTERFACE
("android.content.action.DOCUMENTS_PROVIDER"
). Devi quindi implementare i quattro metodi astratti in DocumentsProvider
:
queryRoots()
- Deve restituire un
Cursor
che descriva tutte le directory principali dello spazio di archiviazione dei documenti, utilizzando le colonne definite inDocumentsContract.Root
. queryChildDocuments()
- Deve restituire un
Cursor
che descriva tutti i file nella directory specificata, utilizzando le colonne definite inDocumentsContract.Document
. queryDocument()
- Deve restituire un
Cursor
che descriva il file specificato utilizzando le colonne definite inDocumentsContract.Document
. openDocument()
- Deve restituire un
ParcelFileDescriptor
che rappresenta il file specificato. Il sistema chiama questo metodo quando l'utente seleziona un file e l'app client ne richiede l'accesso chiamandoopenFileDescriptor()
.
Per ulteriori informazioni, consulta la guida di Storage Access Framework.
Accesso allo spazio di archiviazione esterno
Ora puoi leggere e scrivere file specifici per l'app su supporti di archiviazione esterni secondari, ad esempio quando un dispositivo fornisce sia spazio di archiviazione virtuale sia una scheda SD. Il nuovo metodo getExternalFilesDirs()
funziona come il metodo getExternalFilesDir()
esistente, tranne per il fatto che restituisce un array di oggetti File
. Prima di leggere o scrivere in uno dei percorsi restituiti da questo metodo, passa l'oggetto File
al nuovo metodo getStorageState()
per verificare che lo spazio di archiviazione sia attualmente disponibile.
Anche altri metodi per accedere alla directory della cache e alla directory OBB specifici dell'app ora hanno versioni corrispondenti che forniscono l'accesso ai dispositivi di archiviazione secondari: getExternalCacheDirs()
e getObbDirs()
, rispettivamente.
La prima voce nell'array File
restituito è considerata lo spazio di archiviazione esterno principale del dispositivo, che corrisponde a File
restituito da metodi esistenti come getExternalFilesDir()
.
Nota: a partire da Android 4.4, la piattaforma non richiede più che l'app acquisisca WRITE_EXTERNAL_STORAGE
o READ_EXTERNAL_STORAGE
quando devi accedere solo alle regioni specifiche dell'app dell'unità di archiviazione esterna utilizzando i metodi precedenti. Tuttavia, le autorizzazioni sono necessarie se vuoi accedere alle regioni condivisibili dello spazio di archiviazione esterno, fornite da getExternalStoragePublicDirectory()
.
Adattatori di sincronizzazione
Il nuovo metodo requestSync()
in ContentResolver
semplifica parte della procedura per definire una richiesta di sincronizzazione per il tuo ContentProvider
incapsulando le richieste nel nuovo oggetto SyncRequest
, che puoi creare con SyncRequest.Builder
. Le proprietà in SyncRequest
forniscono la stessa funzionalità delle chiamate di sincronizzazione ContentProvider
esistenti, ma aggiungono la possibilità di specificare che una sincronizzazione deve essere ignorata se la rete è conteggiata, attivando setDisallowMetered()
.
Input utente
Nuovi tipi di sensori
Il nuovo sensore TYPE_GEOMAGNETIC_ROTATION_VECTOR
fornisce dati sul vettore di rotazione in base a un magnetometro, che è un'alternativa utile al sensore TYPE_ROTATION_VECTOR
quando non è disponibile un giroscopio o quando viene utilizzato con gli eventi dei sensori raggruppati per registrare l'orientamento del dispositivo quando lo smartphone è in modalità sospensione. Questo sensore richiede meno energia di TYPE_ROTATION_VECTOR
, ma potrebbe essere soggetto a dati sugli eventi con rumore ed è più efficace quando l'utente è all'aperto.
Android ora supporta anche i sensori di movimento integrati nell'hardware:
TYPE_STEP_DETECTOR
- Questo sensore attiva un evento ogni volta che l'utente fa un passo. A ogni passo dell'utente, questo sensore genera un evento con un valore pari a 1,0 e un timestamp che indica quando si è verificato il passaggio.
TYPE_STEP_COUNTER
- Questo sensore attiva anche un evento per ogni passo rilevato, ma fornisce il numero totale di passi accumulati dal primo rilevamento del sensore da parte di un'app.
Tieni presente che questi due sensori non forniscono sempre gli stessi risultati. Gli eventi TYPE_STEP_COUNTER
si verificano con una latenza superiore rispetto a quelli di TYPE_STEP_DETECTOR
, ma questo perché l'algoritmo TYPE_STEP_COUNTER
esegue più elaborazioni per eliminare i falsi positivi. Pertanto, la generazione di eventi tramite TYPE_STEP_COUNTER
potrebbe essere più lenta, ma i risultati dovrebbero essere più accurati.
Entrambi i sensori di movimento dipendono dall'hardware (Nexus 5 è il primo dispositivo a supportarli), quindi devi verificare la disponibilità con hasSystemFeature()
, utilizzando le costanti FEATURE_SENSOR_STEP_DETECTOR
e FEATURE_SENSOR_STEP_COUNTER
.
Eventi del sensore raggruppati
Per gestire meglio il consumo energetico del dispositivo, le API SensorManager
ora ti consentono di specificare la frequenza con cui il sistema deve inviare alla tua app batch di eventi del sensore. In questo modo, non si riduce il numero di eventi del sensore effettivi disponibili per la tua app per un determinato periodo di tempo, ma si riduce la frequenza con cui il sistema chiama il tuo SensorEventListener
con gli aggiornamenti del sensore. In altre parole, anziché inviare ogni evento all'app nel momento in cui si verifica, il sistema salva tutti gli eventi che si verificano in un determinato periodo di tempo e poi li invia all'app tutti contemporaneamente.
Per fornire il raggruppamento, la classe SensorManager
aggiunge due nuove versioni del metodo registerListener()
che consentono di specificare la "latenza massima dei report". Questo nuovo parametro specifica il ritardo massimo che SensorEventListener
tollererà per l'invio di nuovi eventi del sensore. Ad esempio, se specifichi una latenza batch di un minuto, il sistema pubblicherà l'insieme recente di eventi raggruppati a un intervallo non superiore a un minuto effettuando chiamate consecutive al metodo onSensorChanged()
, una volta per ogni evento raggruppato. Gli eventi del sensore non subiranno mai un ritardo superiore al valore di latenza massima del report, ma potrebbero arrivare prima se altre app hanno richiesto una latenza più breve per lo stesso sensore.
Tuttavia, tieni presente che il sensore invierà alla tua app gli eventi raggruppati in base alla latenza del report solo quando la CPU è attiva. Sebbene un sensore hardware che supporta il raggruppamento continui a raccogliere gli eventi del sensore mentre la CPU è in sospensione, non la risveglierà per inviare all'app gli eventi raggruppati. Quando la memoria del sensore per gli eventi finisce, inizia a eliminare gli eventi più vecchi per salvare quelli più recenti. Per evitare di perdere eventi, riattiva il dispositivo prima che la memoria del sensore sia piena, quindi chiama flush()
per acquisire l'ultimo lotto di eventi. Per stimare quando la memoria sarà piena e deve essere svuotata, chiama getFifoMaxEventCount()
per ottenere il numero massimo di eventi del sensore che può salvare e dividi questo numero per la frequenza con cui la tua app desidera ogni evento. Utilizza questo calcolo per impostare le sveglie con AlarmManager
che richiamano Service
(che implementa SensorEventListener
) per svuotare il sensore.
Nota:non tutti i dispositivi supportano il raggruppamento degli eventi del sensore perché richiede il supporto del sensore hardware. Tuttavia, a partire da Android 4.4, devi sempre utilizzare i nuovi metodi registerListener()
, perché se il dispositivo non supporta il raggruppamento, il sistema ignora in modo elegante l'argomento della latenza del batch e invia gli eventi del sensore in tempo reale.
Identità del controller
Ora Android identifica ogni controller connesso con un numero intero univoco su cui puoi eseguire query con getControllerNumber()
, il che ti consente di associare più facilmente ogni controller a un giocatore diverso in un gioco. Il numero di ciascun controller può cambiare a causa di controller scollegati, collegati o ricollegati dall'utente, quindi devi monitorare il numero del controller corrispondente a ciascun dispositivo di input registrando un'istanza di InputManager.InputDeviceListener
. Poi chiama getControllerNumber()
per ogni InputDevice
quando si verifica una modifica.
Ora i dispositivi connessi forniscono anche ID prodotto e fornitore disponibili da getProductId()
e getVendorId()
. Se devi modificare le mappature delle chiavi in base all'insieme di chiavi disponibili su un dispositivo, puoi eseguire una query sul dispositivo per verificare se alcune chiavi sono disponibili con hasKeys(int...)
.
Interfaccia utente
Modalità a schermo intero immersiva
Per fornire alla tua app un layout che riempia l'intero schermo, il nuovo flag SYSTEM_UI_FLAG_IMMERSIVE
per setSystemUiVisibility()
(se combinato con SYSTEM_UI_FLAG_HIDE_NAVIGATION
) attiva una nuova modalità a schermo intero immersiva. Quando la modalità a schermo intero immersiva è attiva, la tua attività continua a ricevere tutti gli eventi tocco. L'utente può mostrare le barre di sistema con uno scorrimento verso l'interno nella regione in cui appaiono normalmente. In questo modo, il flag SYSTEM_UI_FLAG_HIDE_NAVIGATION
(e il flag SYSTEM_UI_FLAG_FULLSCREEN
, se applicato) viene cancellato, quindi le barre di sistema rimangono visibili. Tuttavia, se vuoi che le barre di sistema vengano nascoste di nuovo dopo alcuni istanti, puoi utilizzare il flag SYSTEM_UI_FLAG_IMMERSIVE_STICKY
.
Barre di sistema traslucide
Ora puoi rendere le barre di sistema parzialmente traslucide con i nuovi temi Theme.Holo.NoActionBar.TranslucentDecor
e Theme.Holo.Light.NoActionBar.TranslucentDecor
. Se attivi le barre di sistema traslucide, il layout riempirà l'area dietro le barre di sistema, quindi devi attivare anche fitsSystemWindows
per la parte del layout che non deve essere coperta dalle barre di sistema.
Se stai creando un tema personalizzato, imposta uno di questi temi come tema principale o includi le proprietà di stile windowTranslucentNavigation
e windowTranslucentStatus
nel tema.
Listener di notifica avanzato
Android 4.3 ha aggiunto le API NotificationListenerService
, che consentono alle app di ricevere informazioni sulle nuove notifiche quando vengono pubblicate dal sistema. In Android 4.4, gli ascoltatori di notifiche possono recuperare metadati aggiuntivi per la notifica e dettagli completi sulle azioni della notifica:
Il nuovo campo Notification.extras
include un Bundle
per fornire al generatore di notifiche metadati aggiuntivi come EXTRA_TITLE
e EXTRA_PICTURE
.
La nuova classe Notification.Action
definisce le caratteristiche di un'azione associata alla notifica, che puoi recuperare dal nuovo campo actions
.
Mirroring di Drawable per i layout RTL
Nelle versioni precedenti di Android, se la tua app include immagini di cui deve essere invertito l'orientamento orizzontale per i layout da destra a sinistra, devi includere l'immagine speculare in una directory di risorse drawables-ldrtl/
. Ora il sistema può specchiare automaticamente le immagini attivando l'attributo autoMirrored
in una risorsa drawable o chiamando setAutoMirrored()
. Se è attivata, l'icona Drawable
viene specchiata automaticamente quando la direzione del layout è da destra a sinistra.
Accessibilità
La classe View
ora ti consente di dichiarare "regioni dinamiche" per parti dell'interfaccia utente che si aggiornano dinamicamente con nuovi contenuti di testo, aggiungendo il nuovo attributo accessibilityLiveRegion
al layout XML o chiamando setAccessibilityLiveRegion()
. Ad esempio, una schermata di accesso con un campo di testo che mostra una notifica "password errata" deve essere contrassegnata come regione in tempo reale, in modo che lo screen reader legga il messaggio quando cambia.
Le app che forniscono un servizio di accessibilità ora possono anche migliorare le proprie funzionalità con nuove API che forniscono informazioni sulle raccolte di visualizzazioni, come le visualizzazioni elenco o griglia, utilizzando AccessibilityNodeInfo.CollectionInfo
e AccessibilityNodeInfo.CollectionItemInfo
.
Autorizzazioni app
Di seguito sono riportate le nuove autorizzazioni che la tua app deve richiedere con il tag <uses-permission>
per utilizzare alcune nuove API:
INSTALL_SHORTCUT
- Consente a un'applicazione di installare una scorciatoia in Avvio app
UNINSTALL_SHORTCUT
- Consente a un'applicazione di disinstallare una scorciatoia in Avvio
TRANSMIT_IR
- Consente a un'applicazione di utilizzare il trasmettitore a infrarossi del dispositivo, se disponibile
Nota: a partire da Android 4.4, la piattaforma non richiede più che la tua app acquisisca WRITE_EXTERNAL_STORAGE
o READ_EXTERNAL_STORAGE
quando vuoi accedere alle regioni specifiche dell'app dell'unità di archiviazione esterna utilizzando metodi come getExternalFilesDir()
. Tuttavia, le autorizzazioni sono comunque necessarie se vuoi accedere alle regioni condivisibili dello spazio di archiviazione esterno fornito da getExternalStoragePublicDirectory()
.
Funzionalità del dispositivo
Di seguito sono riportate le nuove funzionalità del dispositivo che puoi dichiarare con il tag <uses-feature>
per dichiarare i requisiti della tua app e attivare i filtri su Google Play o verificarli in fase di runtime:
FEATURE_CONSUMER_IR
- Il dispositivo è in grado di comunicare con i dispositivi IR di consumo.
FEATURE_DEVICE_ADMIN
- Il dispositivo supporta l'applicazione forzata dei criteri relativi ai dispositivi tramite gli amministratori dei dispositivi.
FEATURE_NFC_HOST_CARD_EMULATION
- Il dispositivo supporta l'emulazione di carte NFC basata su host.
FEATURE_SENSOR_STEP_COUNTER
- Il dispositivo include un contapassi hardware.
FEATURE_SENSOR_STEP_DETECTOR
- Il dispositivo include un rilevatore di passi hardware.
Per una visualizzazione dettagliata di tutte le modifiche all'API in Android 4.4, consulta il report Differenze API.