Livello API: 18
Android 4.3 (JELLY_BEAN_MR2
) è un aggiornamento della release di Jelly Bean che offre nuove funzionalità a utenti e sviluppatori di app. Questo documento offre un'introduzione
alle nuove API più importanti.
In qualità di sviluppatore di app, dovresti scaricare la piattaforma dell'SDK e dell'immagine di sistema Android 4.3 da SDK Manager il prima possibile. Se non hai un dispositivo con Android 4.3 su cui testare la tua app, usa l'immagine di sistema Android 4.3 per testare l'app con l'emulatore Android. Successivamente, crea le tue app sulla piattaforma Android 4.3 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.3, devi impostare targetSdkVersion
su "18"
, installarla su un'immagine di sistema Android 4.3, testarla e pubblicare un aggiornamento con questa modifica.
Puoi utilizzare le API in Android 4.3 e supportare le versioni precedenti aggiungendo al codice condizioni che verificano il livello API di sistema prima di eseguire API non supportate da minSdkVersion
.
Per scoprire di più su come mantenere la compatibilità con le versioni precedenti, consulta la pagina relativa al supporto di diverse versioni della piattaforma.
Nella Support Library Android sono inoltre disponibili varie API che consentono di implementare nuove funzionalità sulle versioni precedenti della piattaforma.
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 che la tua app potrebbe essere influenzata dalle modifiche in Android 4.3.
Se la tua app utilizza intent impliciti...
La tua app potrebbe funzionare in modo anomalo in un ambiente di profilo con limitazioni.
Gli utenti in un ambiente con profilo con limitazioni potrebbero non avere tutte le app Android standard disponibili. Ad esempio, in un profilo con limitazioni potrebbero
essere disattivati il browser web e l'app Fotocamera. La tua app non deve quindi dare supposizioni in merito alle app disponibili, perché se chiami startActivity()
senza verificare se un'app è disponibile per gestire Intent
, la tua app potrebbe arrestarsi in modo anomalo in un profilo con limitazioni.
Se utilizzi un intent implicito, devi sempre verificare che un'app sia disponibile per gestire l'intent chiamando resolveActivity()
o queryIntentActivities()
. Ecco alcuni esempi:
Kotlin
val intent = Intent(Intent.ACTION_SEND) ... if (intent.resolveActivity(packageManager) != null) { startActivity(intent) } else { Toast.makeText(context, R.string.app_not_available, Toast.LENGTH_LONG).show() }
Java
Intent intent = new Intent(Intent.ACTION_SEND); ... if (intent.resolveActivity(getPackageManager()) != null) { startActivity(intent); } else { Toast.makeText(context, R.string.app_not_available, Toast.LENGTH_LONG).show(); }
Se la tua app dipende dagli account...
La tua app potrebbe funzionare in modo anomalo in un ambiente di profilo con limitazioni.
Gli utenti all'interno di un ambiente di profilo con restrizioni non hanno accesso agli account utente per impostazione predefinita.
Se la tua app dipende da un Account
, potrebbe arrestarsi in modo anomalo o comportarsi in modo imprevisto quando viene utilizzata in un profilo con limitazioni.
Se vuoi impedire completamente ai profili con limitazioni di utilizzare la tua app perché dipende dai dati sensibili dell'account, specifica l'attributo android:requiredAccountType
nell'elemento <application>
del file manifest.
Se vuoi consentire ai profili con limitazioni di continuare a utilizzare la tua app anche se non possono creare i propri account, puoi disattivare le funzionalità dell'app che richiedono un account o consentire ai profili con limitazioni di accedere agli account creati dall'utente principale. Per ulteriori informazioni, consulta la sezione riportata di seguito su Supportare gli account in un profilo con limitazioni.
Se la tua app utilizza VideoView...
Il video potrebbe apparire più piccolo su Android 4.3.
Nelle versioni precedenti di Android, il widget VideoView
calcolava erroneamente il valore di "wrap_content"
per layout_height
e layout_width
in modo che fosse uguale a "match_parent"
. Pertanto, se in passato l'utilizzo di "wrap_content"
per l'altezza o la larghezza potrebbe aver fornito il layout video desiderato, ciò potrebbe comportare un video molto più piccolo su Android 4.3 e versioni successive. Per risolvere il problema, sostituisci
"wrap_content"
con "match_parent"
e verifica che il tuo video venga visualizzato come previsto su
Android 4.3 e sulle versioni precedenti.
Profili con limitazioni
Sui tablet Android, gli utenti ora possono creare profili con limitazioni in base all'utente principale. Quando gli utenti creano un profilo con limitazioni, possono attivare limitazioni quali le app disponibili per il profilo. Un nuovo set di API in Android 4.3 consente inoltre di creare impostazioni granulari per le app sviluppate. Ad esempio, utilizzando le nuove API, puoi consentire agli utenti di controllare il tipo di contenuti disponibili all'interno della tua app quando viene eseguita in un ambiente del profilo limitato.
L'interfaccia utente per il controllo delle limitazioni che hai creato è gestita dall'applicazione Impostazioni del sistema. Per mostrare all'utente le impostazioni di limitazione della tua app,
devi dichiarare le limitazioni fornite dalla tua app creando un BroadcastReceiver
che riceva l'intent ACTION_GET_RESTRICTION_ENTRIES
. Il sistema richiama questo intent per interrogare tutte le app per verificare le limitazioni disponibili, quindi crea l'interfaccia utente per consentire all'utente principale di
gestire le limitazioni per ogni profilo con limitazioni.
Nel metodo onReceive()
di BroadcastReceiver
, devi creare un RestrictionEntry
per ogni limitazione fornita dalla tua app. Ogni RestrictionEntry
definisce un titolo, una descrizione e uno dei seguenti tipi di dati:
TYPE_BOOLEAN
per una limitazione vera o falsa.TYPE_CHOICE
per una limitazione con più scelte che si escludono a vicenda (opzioni di pulsanti di opzione).TYPE_MULTI_SELECT
per una limitazione con più scelte che non si escludono a vicenda (scelte di casella di controllo).
Dopodiché inserisci tutti gli oggetti RestrictionEntry
in un ArrayList
e li inserisci nel risultato del ricevitore della trasmissione come valore per l'elemento EXTRA_RESTRICTIONS_LIST
extra.
Il sistema crea l'UI per le limitazioni della tua app nell'app Impostazioni e salva ogni restrizione con la chiave univoca che hai fornito per ogni oggetto RestrictionEntry
. Quando l'utente apre l'app, puoi eseguire una query per conoscere le eventuali restrizioni attuali
chiamando getApplicationRestrictions()
.
Questo restituisce un valore Bundle
contenente le coppie chiave-valore per ogni restrizione definita con gli oggetti RestrictionEntry
.
Se vuoi fornire limitazioni più specifiche che non possono essere gestite da valori booleani, a scelta singola e a scelta multipla, puoi creare un'attività in cui l'utente può specificare le restrizioni e consentire agli utenti di aprire quell'attività dalle impostazioni delle restrizioni. Nel
ricevitore di trasmissione, includi il EXTRA_RESTRICTIONS_INTENT
in più
nel risultato Bundle
. Questo extra deve specificare un Intent
che indichi la classe Activity
da lanciare (utilizza il
metodo putParcelable()
per trasmettere EXTRA_RESTRICTIONS_INTENT
con l'intent).
Quando l'utente principale inserisce la tua attività per impostare limitazioni personalizzate, l'attività deve restituire un risultato contenente i valori della limitazione in un altro modo utilizzando la chiave EXTRA_RESTRICTIONS_LIST
o EXTRA_RESTRICTIONS_BUNDLE
, a seconda che specifichi rispettivamente RestrictionEntry
oggetti o coppie chiave-valore.
Supporto di account in un profilo con limitazioni
Tutti gli account aggiunti all'utente principale sono disponibili per un profilo con limitazioni, ma per impostazione predefinita non sono accessibili dalle API AccountManager
.
Se tenti di aggiungere un account con AccountManager
in un profilo con limitazioni, riceverai un risultato di errore. A causa di queste restrizioni, hai le tre opzioni seguenti:
Per ottenere l'accesso a un account da un profilo con limitazioni, devi aggiungere l'attributo android:restrictedAccountType
al tag <application>:
<application ... android:restrictedAccountType="com.example.account.type" >
Attenzione: l'attivazione di questo attributo consente alla tua app di accedere agli account dell'utente principale dai profili con limitazioni. Dovresti quindi consentire questa operazione solo se le informazioni visualizzate dalla tua app non rivelano informazioni che consentono l'identificazione personale (PII) considerate sensibili. Le impostazioni di sistema comunicheranno all'utente principale che la tua app concede profili con limitazioni ai suoi account, pertanto l'utente dovrebbe essere chiaro che l'accesso all'account è importante per la funzionalità dell'app. Se possibile, dovresti anche fornire controlli delle limitazioni adeguati per l'utente principale che definiscono il livello di accesso all'account consentito nella tua app.
Se vuoi utilizzare gli account, ma non ne hai bisogno per la funzionalità principale
dell'app, puoi controllare la disponibilità degli account e disattivare le funzionalità quando non sono disponibili.
Devi prima verificare se è disponibile un account esistente. In caso contrario, chiedi se è possibile creare un nuovo account chiamando getUserRestrictions()
e controlla l'ulteriore DISALLOW_MODIFY_ACCOUNTS
nel risultato. Se è true
,
devi disattivare qualsiasi funzionalità della tua app che richiede l'accesso agli account.
Ecco alcuni esempi:
Kotlin
val um = context.getSystemService(Context.USER_SERVICE) as UserManager val restrictions: Bundle = um.userRestrictions if (restrictions.getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS, false)) { // cannot add accounts, disable some functionality }
Java
UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE); Bundle restrictions = um.getUserRestrictions(); if (restrictions.getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS, false)) { // cannot add accounts, disable some functionality }
Nota: in questo scenario, non devi dichiarare nuovi attributi nel file manifest.
Se invece è importante che la tua app non sia disponibile per i profili con limitazioni perché dipende da informazioni personali sensibili in un account (e poiché i profili con limitazioni al momento non possono aggiungere nuovi account), aggiungi l'attributo android:requiredAccountType
al tag <application>:
<application ... android:requiredAccountType="com.example.account.type" >
Ad esempio, l'app Gmail utilizza questo attributo per disattivarsi per i profili con limitazioni, in quanto l'email personale del proprietario non deve essere disponibile per i profili con limitazioni.
Wireless e connettività
Bluetooth Low Energy (Smart Ready)
Android ora supporta Bluetooth Low Energy (LE) con nuove API in android.bluetooth
.
Con le nuove API, puoi creare app Android che comunicano con periferiche Bluetooth Low Energy, come i rilevatori del battito cardiaco e i contapassi.
Bluetooth LE è una funzionalità hardware non disponibile su tutti i dispositivi Android, pertanto devi dichiarare nel file manifest un elemento <uses-feature>
per "android.hardware.bluetooth_le"
:
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />
Se conosci già le API Bluetooth classiche di Android, nota che l'utilizzo delle
API Bluetooth LE presenta alcune differenze. L'aspetto più importante è che ora esiste una classe BluetoothManager
che deve essere usata per alcune operazioni di alto livello, come l'acquisizione di un BluetoothAdapter
, la ricezione di un elenco dei dispositivi
connessi e il controllo dello stato di un dispositivo. Ad esempio, ecco come dovresti ottenere ora
BluetoothAdapter
:
Kotlin
val bluetoothManager = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager bluetoothAdapter = bluetoothManager.adapter
Java
final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); bluetoothAdapter = bluetoothManager.getAdapter();
Per scoprire le periferiche Bluetooth LE, chiama startLeScan()
su BluetoothAdapter
, passando un'implementazione
dell'interfaccia BluetoothAdapter.LeScanCallback
. Quando l'adattatore Bluetooth rileva una periferica Bluetooth LE, l'implementazione BluetoothAdapter.LeScanCallback
riceve una chiamata al metodo onLeScan()
. Questo metodo fornisce un oggetto BluetoothDevice
che rappresenta il dispositivo rilevato, il valore RSSI del dispositivo e un array di byte contenente il record pubblicitario del dispositivo.
Se vuoi analizzare solo tipi specifici di periferiche, puoi chiamare startLeScan()
e includere un array di oggetti UUID
che specificano i servizi GATT supportati dalla tua app.
Nota: puoi cercare solo dispositivi Bluetooth LE o dispositivi Bluetooth classici utilizzando le API precedenti. Non puoi cercare dispositivi LE e Bluetooth Classic contemporaneamente.
Per connetterti a una periferica Bluetooth LE, chiama connectGatt()
sull'oggetto BluetoothDevice
corrispondente, passando un'implementazione di BluetoothGattCallback
. La tua implementazione di BluetoothGattCallback
riceve callback relativi allo stato di connettività con il dispositivo e altri eventi. È durante il callback onConnectionStateChange()
che puoi iniziare a comunicare con il dispositivo se il metodo trasmette il nuovo stato STATE_CONNECTED
.
L'accesso alle funzionalità Bluetooth su un dispositivo richiede anche che l'app richieda determinate autorizzazioni utente Bluetooth. Per ulteriori informazioni, consulta la guida all'API Bluetooth Low Energy.
Modalità di sola ricerca di reti Wi-Fi
Quando cerca di identificare la posizione dell'utente, Android potrebbe usare il Wi-Fi per determinare la posizione scansionando i punti di accesso nelle vicinanze. Tuttavia, spesso gli utenti tengono disattivato il Wi-Fi per risparmiare batteria e di conseguenza i dati sulla posizione sono meno precisi. Android ora include una modalità di sola scansione che consente al Wi-Fi del dispositivo di eseguire la scansione dei punti di accesso per ottenere la posizione senza connettersi a un punto di accesso, riducendo così l'utilizzo della batteria.
Se vuoi acquisire la posizione dell'utente, ma il Wi-Fi è attualmente disattivato, puoi richiedere all'utente
di attivare la modalità di sola ricerca di reti Wi-Fi chiamando startActivity()
con l'azione ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE
.
Configurazione Wi-Fi
Le nuove API WifiEnterpriseConfig
consentono ai servizi orientati all'azienda di
automatizzare la configurazione Wi-Fi per i dispositivi gestiti.
Risposta rapida per le chiamate in arrivo
A partire da Android 4.0, una funzione chiamata "Risposta rapida" consente agli utenti di rispondere alle chiamate in arrivo con un messaggio immediato senza dover rispondere alla chiamata o sbloccare il dispositivo.
Finora, questi messaggi rapidi venivano sempre gestiti dall'app di messaggistica predefinita. Ora, qualsiasi app
può dichiarare la propria capacità di gestire questi messaggi creando un Service
con un filtro per intent per ACTION_RESPOND_VIA_MESSAGE
.
Quando l'utente risponde a una chiamata in arrivo con una risposta rapida, l'app Telefono invia l'intent ACTION_RESPOND_VIA_MESSAGE
con un URI che descrive il destinatario (il chiamante) e l'ulteriore EXTRA_TEXT
con il messaggio che l'utente vuole inviare. Quando il servizio riceve l'intent, dovrebbe consegnare il messaggio e interrompersi immediatamente (l'app non deve mostrare un'attività).
Per ricevere questo intent, devi dichiarare l'autorizzazione SEND_RESPOND_VIA_MESSAGE
.
Multimediale
Miglioramenti a MediaExtractor e MediaCodec
Ora è più semplice scrivere i tuoi player Dynamic Adaptive Streaming over HTTP (DASH) in base allo standard ISO/IEC 23009-1 utilizzando le API esistenti in MediaCodec
e MediaExtractor
. Il framework alla base di queste API è stato aggiornato per supportare l'analisi di file MP4 frammentati, ma la tua app è ancora responsabile dell'analisi dei metadati MPD e del passaggio dei singoli stream a MediaExtractor
.
Se vuoi utilizzare DASH con contenuti criptati, tieni presente che il metodo getSampleCryptoInfo()
restituisce i metadati MediaCodec.CryptoInfo
che descrivono la struttura di ogni campione di contenuti multimediali criptati. Inoltre, il metodo getPsshInfo()
è stato aggiunto a
MediaExtractor
per permetterti di accedere ai metadati PSSH per i tuoi contenuti multimediali DASH.
Questo metodo restituisce una mappa di oggetti UUID
ai byte, dove UUID
specifica lo schema di crittografia e i byte sono i dati specifici di quello schema.
DRM multimediale
La nuova classe MediaDrm
fornisce una soluzione modulare per la gestione dei diritti digitali (DRM) con i tuoi contenuti multimediali, separando i problemi DRM dalla riproduzione di contenuti multimediali. Ad esempio, questa separazione delle API consente di riprodurre contenuti criptati con Widevine senza dover utilizzare il formato multimediale Widevine. Questa soluzione DRM supporta anche la crittografia comune DASH per consentirti di utilizzare diversi schemi DRM con i contenuti in streaming.
Puoi utilizzare MediaDrm
per ottenere messaggi di richiesta chiave opachi ed elaborare
messaggi di risposta chiave dal server per l'acquisizione e il provisioning delle licenze. La tua app
è responsabile della gestione della comunicazione di rete con i server; la classe MediaDrm
consente solo di generare ed elaborare i messaggi.
Le API MediaDrm
sono destinate a essere utilizzate insieme alle
API MediaCodec
introdotte in Android 4.1 (livello API 16),
tra cui MediaCodec
per la codifica e decodifica dei contenuti, MediaCrypto
per la gestione dei contenuti criptati e MediaExtractor
per l'estrazione e la rimozione dei contenuti.
Devi prima creare gli oggetti MediaExtractor
e
MediaCodec
. Puoi quindi accedere all'identificazione dello schema DRM UUID
, in genere dai metadati nei contenuti, e utilizzarla per creare un'istanza di un oggetto MediaDrm
con il relativo costruttore.
Codifica video da un
Android 4.1 (livello API 16) ha aggiunto la classe MediaCodec
per la codifica di basso livello e la decodifica di contenuti multimediali. Durante la codifica dei video, Android 4.1 richiedeva che i contenuti multimediali venissero forniti con un array ByteBuffer
, mentre Android 4.3 consente ora di utilizzare un Surface
come input per un codificatore. Ad esempio, questo ti consente di codificare l'input
da un file video esistente o utilizzando frame generati da OpenGL ES.
Per utilizzare un Surface
come input per il tuo codificatore, devi prima chiamare configure()
per MediaCodec
.
Quindi chiama createInputSurface()
per ricevere Surface
tramite cui puoi trasmettere in streaming i tuoi contenuti multimediali.
Ad esempio, puoi utilizzare il valore Surface
specificato come finestra per un contesto OpenGL
passandolo a eglCreateWindowSurface()
. Durante il rendering della superficie, chiama eglSwapBuffers()
per passare il frame a MediaCodec
.
Per iniziare la codifica, chiama start()
sul MediaCodec
. Al termine, chiama signalEndOfInputStream()
per terminare la codifica e chiama release()
sul
Surface
.
Muxing di contenuti multimediali
La nuova classe MediaMuxer
consente il multiplexing tra uno stream audio e uno stream video. Queste API fungono da controparte alla classe MediaExtractor
aggiunta in Android 4.2 per il de-multiplexing (demuxing) dei contenuti multimediali.
I formati di output supportati sono definiti in MediaMuxer.OutputFormat
. Attualmente, MP4 è l'unico formato di output supportato e MediaMuxer
supporta attualmente uno stream audio e/o uno stream video alla volta.
MediaMuxer
è progettato principalmente per funzionare con MediaCodec
,
quindi puoi eseguire l'elaborazione video tramite MediaCodec
, quindi salvare l'output
in un file MP4 fino al giorno MediaMuxer
. Puoi anche utilizzare MediaMuxer
insieme a MediaExtractor
per modificare i contenuti multimediali senza dover codificare o decodificare.
Avanzamento della riproduzione e scrubbing per RemoteControlClient
In Android 4.0 (livello API 14), l'elemento RemoteControlClient
è stato aggiunto per abilitare i controlli per la riproduzione di contenuti multimediali dai client di controllo remoto come i controlli disponibili nella schermata di blocco. Android 4.3 consente ora a questi controller di visualizzare la posizione di riproduzione e i controlli per eseguire lo scrubbing della riproduzione. Se hai attivato il controllo remoto per la tua
app multimediale con le API RemoteControlClient
, puoi consentire lo scrubbing della riproduzione
implementando due nuove interfacce.
Innanzitutto, devi attivare il flag FLAG_KEY_MEDIA_POSITION_UPDATE
passandolo a
setTransportControlsFlags()
.
Quindi, implementa le seguenti due nuove interfacce:
RemoteControlClient.OnGetPlaybackPositionListener
- È incluso il callback
onGetPlaybackPosition()
, che richiede la posizione corrente dei contenuti multimediali quando il telecomando deve aggiornare l'avanzamento nella sua UI. RemoteControlClient.OnPlaybackPositionUpdateListener
- È incluso il callback
onPlaybackPositionUpdate()
, che indica alla tua app il nuovo codice temporale dei contenuti multimediali quando l'utente esegue lo scrubbing della riproduzione con l'interfaccia utente del telecomando.Dopo aver aggiornato la riproduzione con la nuova posizione, chiama
setPlaybackState()
per indicare il nuovo stato di riproduzione, la nuova posizione e la nuova velocità.
Una volta definite queste interfacce, puoi impostarle per RemoteControlClient
chiamando rispettivamente setOnGetPlaybackPositionListener()
e
setPlaybackPositionUpdateListener()
.
Grafica
Supporto per OpenGL ES 3.0
Android 4.3 aggiunge interfacce Java e supporto nativo per OpenGL ES 3.0. La nuova funzionalità chiave fornita in OpenGL ES 3.0 include:
- Accelerazione degli effetti visivi avanzati
- Compressione delle texture ETC2/EAC di alta qualità come funzionalità standard
- Una nuova versione del linguaggio di Shading GLSL ES con supporto per numeri interi e in virgola mobile a 32 bit
- Rendering avanzato delle texture
- Standardizzazione più ampia delle dimensioni delle texture e dei formati del buffer di rendering
L'interfaccia Java per OpenGL ES 3.0 su Android è fornita con GLES30
.
Quando usi OpenGL ES 3.0, assicurati di dichiararlo nel file manifest con il tag <uses-feature> e l'attributo android:glEsVersion
. Ecco alcuni esempi:
<manifest> <uses-feature android:glEsVersion="0x00030000" /> ... </manifest>
Ricordati di specificare il contesto OpenGL ES chiamando setEGLContextClientVersion()
,
passando 3
come versione.
Per ulteriori informazioni sull'utilizzo di OpenGL ES, incluso come verificare la versione OpenID ES supportata del dispositivo in fase di runtime, consulta la guida all'API OpenGL ES.
Mipmapping per disegni
L'utilizzo di una mipmap come origine per la tua bitmap o disegnabile è un modo semplice per fornire un'immagine di qualità e varie scale di immagine, che possono essere particolarmente utili se prevedi che l'immagine venga ridimensionata durante un'animazione.
Android 4.2 (livello API 17) ha aggiunto il supporto per i mipmap nella classe Bitmap
: Android scambia le immagini MIP in Bitmap
quando hai fornito un'origine Mipmap e hai attivato setHasMipMap()
. Ora in Android 4.3 puoi abilitare le mipmap per un oggetto BitmapDrawable
, fornendo un asset mipmap e impostando l'attributo android:mipMap
in un file di risorse bitmap oppure chiamando hasMipMap()
.
Interfaccia utente
Visualizza overlay
La nuova classe ViewOverlay
fornisce un livello trasparente sopra a View
sul quale puoi aggiungere contenuti visivi e che non influisce sulla gerarchia del layout. Puoi ricevere un ViewOverlay
a qualsiasi View
chiamando il numero getOverlay()
. L'overlay ha sempre le stesse dimensioni e la stessa posizione della visualizzazione host (la vista da cui è stato creato), il che ti consente di aggiungere contenuti che appaiono di fronte a quest'ultima, ma che non possono estendere i suoi limiti.
L'utilizzo di ViewOverlay
è particolarmente utile quando vuoi creare animazioni, come lo scorrimento di una vista all'esterno del contenitore o lo spostamento di elementi sullo schermo senza influire sulla gerarchia delle visualizzazioni. Tuttavia, poiché l'area utilizzabile di un overlay è limitata alla stessa area della vista host, se vuoi animare una vista che si sposta al di fuori della sua posizione nel layout, devi utilizzare un overlay di una vista principale con i limiti di layout desiderati.
Quando crei un overlay per una visualizzazione widget, ad esempio Button
, puoi aggiungere oggetti Drawable
all'overlay chiamando add(Drawable)
. Se chiami getOverlay()
per una visualizzazione del layout, ad esempio RelativeLayout
, l'oggetto restituito è un ViewGroupOverlay
. La classe ViewGroupOverlay
è una sottoclasse di ViewOverlay
che ti consente anche di aggiungere oggetti View
chiamando add(View)
.
Nota: tutti i disegni e le visualizzazioni che aggiungi a un overlay sono solo visivi. Non possono ricevere eventi di input o di interesse.
Ad esempio, il seguente codice anima una vista che scorre verso destra posizionando la vista nell'overlay della vista principale e poi eseguendo un'animazione di traduzione su quella vista:
Kotlin
val view: View? = findViewById(R.id.view_to_remove) val container: ViewGroup? = view?.parent as ViewGroup container?.apply { overlay.add(view) ObjectAnimator.ofFloat(view, "translationX", right.toFloat()) .start() }
Java
View view = findViewById(R.id.view_to_remove); ViewGroup container = (ViewGroup) view.getParent(); container.getOverlay().add(view); ObjectAnimator anim = ObjectAnimator.ofFloat(view, "translationX", container.getRight()); anim.start();
Layout limiti ottici
Per le viste che contengono immagini di sfondo con nove patch, ora puoi specificare che devono essere allineate alle viste vicine in base ai limiti "ottici" dell'immagine di sfondo anziché ai limiti "clip" della vista.
Ad esempio, le figure 1 e 2 mostrano ciascuna lo stesso layout, ma la versione nella figura 1 utilizza limiti di clip (il comportamento predefinito), mentre la figura 2 utilizza limiti ottici. Poiché le immagini con nove patch utilizzate per il pulsante e la cornice digitale includono la spaziatura interna attorno ai bordi, non sembrano allinearsi tra loro o con il testo quando utilizzi i margini dei clip.
Nota: negli screenshot nelle figure 1 e 2 è abilitata l'impostazione per sviluppatori "Mostra limiti di layout". Per ogni visualizzazione, le linee rosse indicano i limiti ottici, le linee blu indicano i margini del clip e le linee rosa indicano i margini.
![](https://developer.android.google.cn/static/images/tools/clipbounds_2x.png?authuser=7&hl=it)
Figura 1. Layout utilizzando i margini dei clip (impostazione predefinita).
![](https://developer.android.google.cn/static/images/tools/opticalbounds_2x.png?authuser=7&hl=it)
Figura 2. Layout con limiti ottici.
Per allineare le visualizzazioni in base ai rispettivi limiti ottici, imposta l'attributo android:layoutMode
su "opticalBounds"
in uno dei layout principali. Ecco alcuni esempi:
<LinearLayout android:layoutMode="opticalBounds" ... >
![](https://developer.android.google.cn/static/images/tools/ninepatch_opticalbounds_2x.png?authuser=7&hl=it)
Figura 3. Vista ingrandita della patch a nove punti del pulsante Holo con limiti ottici.
Affinché questo comando funzioni, le immagini delle nove patch applicate allo sfondo delle viste devono specificare i limiti ottici utilizzando linee rosse lungo la parte inferiore e destra del file nove patch (come mostrato nella Figura 3). Le linee rosse indicano l'area che deve essere sottratta dai limiti del clip, lasciando i limiti ottici dell'immagine.
Quando attivi i limiti ottici per un elemento ViewGroup
nel layout, tutte le visualizzazioni discendenti ereditano la modalità di layout dei limiti ottici, a meno che non la sostituisci per un gruppo impostando android:layoutMode
su "clipBounds"
. Tutti gli elementi del layout rispettano inoltre i limiti ottici delle viste secondarie, adattando i propri limiti in base ai limiti ottici delle viste al loro interno. Tuttavia, gli elementi di layout (sottoclassi ViewGroup
)
attualmente non supportano i limiti ottici per le immagini con nove patch applicate al proprio sfondo.
Se crei una vista personalizzata sottoclasse View
, ViewGroup
o una delle sue sottoclassi, la visualizzazione erediterà questi comportamenti relativi al vincolo ottico.
Nota: tutti i widget supportati dal tema Holo sono stati aggiornati con limiti ottici, inclusi Button
, Spinner
, EditText
e altri. Puoi quindi trarre vantaggio immediatamente dall'impostazione dell'attributo android:layoutMode
su "opticalBounds"
se la tua app applica un tema Holo (Theme.Holo
, Theme.Holo.Light
e così via).
Per specificare limiti ottici per le tue immagini con nove patch con lo strumento Disegna 9 patch, tieni premuto Ctrl quando fai clic sui pixel del bordo.
Animazione per i valori rettangoli
Ora puoi animare tra due valori Rect
con il nuovo RectEvaluator
. Questa nuova classe è un'implementazione di TypeEvaluator
che puoi passare a ValueAnimator.setEvaluator()
.
Collegamento finestra e listener dello stato attivo
In precedenza, se volevi ascoltare il momento in cui la vista era collegata/scollegata dalla finestra o
quando lo stato attivo cambiava, dovevi eseguire l'override della classe View
per
implementare onAttachedToWindow()
e onDetachedFromWindow()
o onWindowFocusChanged()
, rispettivamente.
Ora, per ricevere eventi di collegamento e scollegamento, puoi implementare ViewTreeObserver.OnWindowAttachListener
e impostarlo in una vista con addOnWindowAttachListener()
.
Per ricevere eventi di interesse, puoi implementare ViewTreeObserver.OnWindowFocusChangeListener
e impostarlo in una vista con
addOnWindowFocusChangeListener()
.
Supporto dell'overscan TV
Per assicurarti che l'app riempia tutto lo schermo su tutti i televisori, ora puoi attivare l'overscan per il layout dell'app. La modalità di overscan è determinata dal flag FLAG_LAYOUT_IN_OVERSCAN
, che puoi abilitare con temi della piattaforma come
Theme_DeviceDefault_NoActionBar_Overscan
o attivando lo stile
windowOverscan
in un tema personalizzato.
Orientamento dello schermo
L'attributo <activity>
del tag screenOrientation
ora supporta valori aggiuntivi per rispettare la preferenza dell'utente per la rotazione automatica:
"userLandscape"
- Il comportamento è uguale a quello di
"sensorLandscape"
, tranne se l'utente disattiva la rotazione automatica, viene bloccato nel normale orientamento orizzontale e non può capovolgere. "userPortrait"
- Ha lo stesso comportamento di
"sensorPortrait"
, tranne se l'utente disattiva la rotazione automatica, si blocca nel normale orientamento verticale e non si capovolge. "fullUser"
- Ha lo stesso comportamento di
"fullSensor"
e consente la rotazione in tutte e quattro le direzioni; tuttavia, se l'utente disattiva la rotazione automatica, si blocca nell'orientamento che preferisce.
Inoltre, ora puoi anche dichiarare "locked"
per bloccare l'orientamento della tua app
nell'orientamento corrente dello schermo.
Animazioni di rotazione
Il nuovo campo rotationAnimation
in WindowManager
ti consente di selezionare una delle tre animazioni da utilizzare quando il sistema cambia l'orientamento dello schermo. Le tre animazioni sono:
Nota:queste animazioni sono disponibili solo se hai impostato la tua attività per utilizzare la modalità "a schermo intero", che puoi attivare con temi come Theme.Holo.NoActionBar.Fullscreen
.
Ad esempio, ecco come attivare l'animazione "dissolvenza incrociata":
Kotlin
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val params: WindowManager.LayoutParams = window.attributes params.rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE window.attributes = params ... }
Java
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); WindowManager.LayoutParams params = getWindow().getAttributes(); params.rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE; getWindow().setAttributes(params); ... }
Input utente
Nuovi tipi di sensori
Il nuovo sensore TYPE_GAME_ROTATION_VECTOR
ti consente di rilevare le rotazioni del dispositivo senza preoccuparti delle interferenze magnetiche. A differenza del sensore TYPE_ROTATION_VECTOR
, il sensore TYPE_GAME_ROTATION_VECTOR
non si basa sul nord magnetico.
I nuovi sensori TYPE_GYROSCOPE_UNCALIBRATED
e TYPE_MAGNETIC_FIELD_UNCALIBRATED
forniscono dati non elaborati dei sensori senza
considerare le stime dei bias. In altre parole, i sensori TYPE_GYROSCOPE
e TYPE_MAGNETIC_FIELD
esistenti forniscono dati dei sensori che tengono conto del bias stimato, rispettivamente, per la deriva del giroscopio e il ferro duro all'interno del dispositivo. Le nuove versioni "non calibrate" di questi sensori forniscono invece
i dati non elaborati dei sensori e offrono separatamente i valori di bias stimati. Questi sensori ti consentono di
fornire una calibrazione personalizzata per i dati dei sensori migliorando il bias stimato con dati esterni.
Listener di notifica
Android 4.3 aggiunge una nuova classe di servizio, NotificationListenerService
, che consente all'app di ricevere informazioni sulle nuove notifiche non appena vengono pubblicate dal sistema.
Se al momento la tua app utilizza le API dei servizi di accessibilità per accedere alle notifiche di sistema, devi aggiornare l'app in modo che utilizzi queste API.
Provider di contatti
Query per "contatti"
La nuova query del fornitore di contatti, Contactables.CONTENT_URI
, offre un modo efficiente per ottenere un Cursor
contenente tutti gli indirizzi email e i numeri di telefono appartenenti a tutti i contatti che corrispondono alla query specificata.
Query per i delta dei contatti
Al Provider di contatti sono state aggiunte nuove API che ti consentono di eseguire in modo efficiente query sulle modifiche recenti ai dati dei contatti. In precedenza, la tua app poteva ricevere una notifica quando cambiava qualcosa nei dati dei contatti, ma non sapvi esattamente cosa è cambiato e dovevi recuperare tutti i contatti e ripetere l'iterazione per scoprire la modifica.
Per monitorare le modifiche a inserti e aggiornamenti, ora puoi includere il parametro CONTACT_LAST_UPDATED_TIMESTAMP
nella tua selezione per eseguire una query solo sui contatti che sono stati modificati dall'ultima volta che hai inviato una query al fornitore.
Per tenere traccia dei contatti eliminati, la nuova tabella ContactsContract.DeletedContacts
fornisce un log dei contatti che sono stati eliminati (ma ogni contatto eliminato viene conservato in questa tabella per un periodo di tempo limitato). Come CONTACT_LAST_UPDATED_TIMESTAMP
, puoi utilizzare il nuovo parametro di selezione, CONTACT_DELETED_TIMESTAMP
per verificare quali contatti sono stati eliminati dall'ultima volta che hai inviato una richiesta al provider. La tabella contiene anche la costante DAYS_KEPT_MILLISECONDS
che contiene il numero di giorni (in millisecondi) durante i quali il log verrà conservato.
Inoltre, il fornitore di contatti ora trasmette l'azione CONTACTS_DATABASE_CREATED
quando l'utente cancella lo spazio di archiviazione dei contatti tramite il menu delle impostazioni di sistema, ricreando di fatto il database del fornitore di contatti. È destinato a segnalare alle app che devono eliminare tutti i dati di contatto
archiviati e ricaricarli con una nuova query.
Per un codice di esempio che utilizza queste API per verificare la presenza di modifiche ai contatti, cerca nell'esempio di ApiDemos disponibile nel download degli esempi di SDK.
Localizzazione
Supporto migliorato per il testo bidirezionale
Le versioni precedenti di Android supportano le lingue e il layout da destra a sinistra (RTL), ma a volte non gestiscono correttamente il testo in direzioni miste. Per questo motivo, Android 4.3 aggiunge le API BidiFormatter
, che consentono di formattare correttamente il testo con contenuti in direzioni opposte senza alterarne le parti.
Ad esempio, se vuoi creare una frase con una variabile stringa, come "Forse cercavi:
15 Bay Street, Laurel, CA?", di solito passi una risorsa stringa localizzata e la variabile a
String.format()
:
Kotlin
val suggestion = String.format(resources.getString(R.string.did_you_mean), address)
Java
Resources res = getResources(); String suggestion = String.format(res.getString(R.string.did_you_mean), address);
Tuttavia, se la lingua è ebraico, la stringa formattata avrà il seguente aspetto:
L'account ufficiale è stato disattivato a 15 Bay Street, Laurel, California?
Sbagliato perché il numero "15" dovrebbe essere lasciato di "Bay Street". La soluzione consiste nell'utilizzare BidiFormatter
e il relativo metodo unicodeWrap()
. Ad esempio, il codice riportato sopra diventa:
Kotlin
val bidiFormatter = BidiFormatter.getInstance() val suggestion = String.format( resources.getString(R.string.did_you_mean), bidiFormatter.unicodeWrap(address) )
Java
Resources res = getResources(); BidiFormatter bidiFormatter = BidiFormatter.getInstance(); String suggestion = String.format(res.getString(R.string.did_you_mean), bidiFormatter.unicodeWrap(address));
Per impostazione predefinita, unicodeWrap()
utilizza
la prima euristica di stima della direzionalità efficace, che può generare errori se il primo
indicatore per la direzione del testo non rappresenta la direzione appropriata per il contenuto nel suo complesso.
Se necessario, puoi specificare un'euristica diversa passando una delle costanti TextDirectionHeuristic
da TextDirectionHeuristics
a unicodeWrap()
.
Nota: queste nuove API sono disponibili anche per le versioni precedenti di Android tramite la Support Library di Android, con la classe BidiFormatter
e le API correlate.
Servizi di accessibilità
Gestire gli eventi chiave
Ora un AccessibilityService
può ricevere un callback per gli eventi di input chiave con il metodo di callback onKeyEvent()
. Ciò consente al tuo servizio di accessibilità di gestire l'input dei dispositivi di input basati su tasti, ad esempio una tastiera, e di tradurre questi eventi in azioni speciali che in precedenza erano possibili solo con l'input tocco o il d-pad del dispositivo.
Seleziona testo e copia/incolla
L'AccessibilityNodeInfo
ora fornisce API che consentono a un AccessibilityService
di selezionare, tagliare, copiare e incollare il testo in un nodo.
Per specificare la selezione di testo da tagliare o copiare, il servizio di accessibilità può utilizzare la nuova
azione, ACTION_SET_SELECTION
, trasmettendo
la posizione di inizio e fine della selezione con ACTION_ARGUMENT_SELECTION_START_INT
e ACTION_ARGUMENT_SELECTION_END_INT
.
In alternativa, puoi selezionare il testo manipolando la posizione del cursore con l'azione esistente ACTION_NEXT_AT_MOVEMENT_GRANULARITY
(in precedenza solo per spostare la posizione del cursore) e aggiungendo l'argomento ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
.
Puoi tagliare o copiare con ACTION_CUT
,
ACTION_COPY
e poi incollare con
ACTION_PASTE
in un secondo momento.
Nota: queste nuove API sono disponibili anche per le versioni precedenti di Android tramite la Libreria Support di Android, con la classe AccessibilityNodeInfoCompat
.
Dichiara le funzioni di accessibilità
A partire dalla versione 4.3 di Android, un servizio di accessibilità deve dichiarare le funzionalità di accessibilità nel file di metadati per poter utilizzare determinate funzioni. Se la funzionalità non è richiesta nel file dei metadati, la funzionalità sarà inutilizzabile. Per dichiarare le capacità di accessibilità del servizio, devi utilizzare attributi XML che corrispondano alle varie costanti di "capacità" nella classe AccessibilityServiceInfo
.
Ad esempio, se un servizio non richiede la funzionalità flagRequestFilterKeyEvents
, non riceverà eventi chiave.
Test e debug
Test automatici dell'interfaccia utente
La nuova classe UiAutomation
fornisce API che consentono di simulare le azioni degli utenti
per l'automazione dei test. Grazie all'utilizzo delle API AccessibilityService
della piattaforma, le API UiAutomation
consentono di ispezionare i contenuti dello schermo e inserire eventi arbitrari di tastiera e tocco.
Per ottenere un'istanza di UiAutomation
, chiama Instrumentation.getUiAutomation()
. Affinché questa operazione funzioni, devi fornire l'opzione -w
con il comando instrument
quando esegui InstrumentationTestCase
da adb shell
.
Con l'istanza UiAutomation
, puoi eseguire eventi arbitrari per testare la tua app chiamando executeAndWaitForEvent()
, passando un Runnable
da eseguire, un periodo di timeout per l'operazione e un'implementazione dell'interfaccia UiAutomation.AccessibilityEventFilter
. È nell'ambito dell'implementazione UiAutomation.AccessibilityEventFilter
che riceverai una chiamata che ti consente di filtrare gli eventi di tuo interesse e determinare l'esito positivo o negativo di un determinato scenario di test.
Per osservare tutti gli eventi durante un test, crea un'implementazione di UiAutomation.OnAccessibilityEventListener
e passala a setOnAccessibilityEventListener()
.
L'interfaccia listener riceve quindi una chiamata a onAccessibilityEvent()
ogni volta che si verifica un evento, ricevendo un oggetto AccessibilityEvent
che descrive l'evento.
Le API UiAutomation
espongono a un livello molto basso una serie di altre operazioni per incoraggiare lo sviluppo di strumenti di test dell'interfaccia utente come uiautomator. Ad esempio,
UiAutomation
può anche:
- Inserisci eventi di input
- Modificare l'orientamento dello schermo
- Acquisisci screenshot
Inoltre, soprattutto per gli strumenti di test dell'interfaccia utente, le API UiAutomation
operano
attraverso i confini delle applicazioni, a differenza di quelli in Instrumentation
.
Eventi di Systrace per le app
Android 4.3 aggiunge la classe Trace
con due metodi statici, beginSection()
e endSection()
, che consentono di definire blocchi di codice da includere nel report systrace. Creando sezioni di codice tracciabile nell'app, i log di systrace forniscono un'analisi molto più dettagliata del punto in cui si verifica il rallentamento all'interno dell'app.
Per informazioni sull'utilizzo dello strumento Systrace, consulta la pagina relativa all'analisi del display e delle prestazioni con Systrace.
Sicurezza
Keystore Android per chiavi private delle app
Android ora offre nella struttura KeyStore
un provider di sicurezza Java personalizzato, chiamato Android Key Store, che ti consente di generare e salvare chiavi private che potrebbero essere visualizzate e utilizzate solo dalla tua app. Per caricare l'Android Key Store, passa "AndroidKeyStore"
a KeyStore.getInstance()
.
Per gestire le credenziali private della tua app nell'Android Key Store, genera una nuova chiave con KeyPairGenerator
con KeyPairGeneratorSpec
. Per prima cosa, recupera un'istanza di KeyPairGenerator
chiamando getInstance()
. Quindi chiama
initialize()
, passando un'istanza di
KeyPairGeneratorSpec
, operazione che puoi ottenere utilizzando
KeyPairGeneratorSpec.Builder
.
Infine, richiedi il tuo KeyPair
chiamando il numero generateKeyPair()
.
Archivio credenziali hardware
Android ora supporta anche l'archiviazione basata sull'hardware per le tue credenziali KeyChain
, offrendo maggiore sicurezza rendendo le chiavi non disponibili per l'estrazione. In altre parole, una volta che le chiavi si trovano in un archivio chiavi supportato dall'hardware (Secure Element, TPM o TrustZone), possono essere utilizzate per operazioni di crittografia, ma non è possibile esportare il materiale della chiave privata. Anche il kernel del sistema operativo
non può accedere a questo materiale della chiave. Anche se non tutti i dispositivi Android supportano lo spazio di archiviazione sull'hardware, puoi verificare in fase di runtime se lo spazio di archiviazione supportato dall'hardware è disponibile chiamando KeyChain.IsBoundKeyAlgorithm()
.
Dichiarazioni manifest
Funzionalità richieste dichiarabili
I seguenti valori sono ora supportati nell'elemento <uses-feature>
, così puoi assicurarti che la tua app sia installata solo su dispositivi che forniscono le funzionalità necessarie per l'app.
FEATURE_APP_WIDGETS
- Dichiara che la tua app fornisce un widget dell'app e deve essere installata solo su dispositivi che
includono una schermata Home o una posizione simile in cui gli utenti possono incorporare i widget dell'app.
Esempio:
<uses-feature android:name="android.software.app_widgets" android:required="true" />
FEATURE_HOME_SCREEN
- Dichiara che la tua app funge da sostituzione della schermata Home e deve essere installata soltanto su
dispositivi che supportano le app della schermata Home di terze parti.
Esempio:
<uses-feature android:name="android.software.home_screen" android:required="true" />
FEATURE_INPUT_METHODS
- Dichiara che la tua app fornisce un metodo di immissione personalizzato (una tastiera creata con
InputMethodService
) e deve essere installata soltanto su dispositivi che supportano metodi di immissione di terze parti. Esempio:<uses-feature android:name="android.software.input_methods" android:required="true" />
FEATURE_BLUETOOTH_LE
- Dichiara che la tua app utilizza le API Bluetooth Low Energy e deve essere installata solo su dispositivi
in grado di comunicare con altri dispositivi tramite Bluetooth Low Energy.
Esempio:
<uses-feature android:name="android.software.bluetooth_le" android:required="true" />
Autorizzazioni utente
I seguenti valori sono ora supportati nella <uses-permission>
per dichiarare le autorizzazioni richieste dalla tua app per accedere a determinate API.
BIND_NOTIFICATION_LISTENER_SERVICE
- Obbligatorio per utilizzare le nuove API
NotificationListenerService
. SEND_RESPOND_VIA_MESSAGE
- Obbligatorio per ricevere l'intent
ACTION_RESPOND_VIA_MESSAGE
.
Per una visualizzazione dettagliata di tutte le modifiche all'API in Android 4.3, consulta il report Differenze API.