2013-01-16 8 views
10

Poiché Android 4.2 se un utente scarica alcuni file nel browser, viene utilizzato DownloadManager. Se l'utente fa clic sulla notifica di "download completo", l'intento è sempre stato lanciato. Prima di Android 4.2 l'intento usato per avere il percorso del file scaricato nel contenuto, in modo tale che:Recupera il percorso del file dall'intento di DownloadManager catturato

intent.getData() 

sarebbe restituire una stringa come file:///storage/emulated/0/Download/some_file.ext. Tuttavia, poiché Android 4.2 il gestore di download trasmette e intenti con uno schema content, ad esempio content://downloads/all_downloads/2334.

Come si recupera il percorso del file locale per un file scaricato?

ho provato la seguente:

public static String getRealPathFromURI(Uri contentUri, Activity activity) { 
    DownloadManager downloadManager = (DownloadManager) activity.getSystemService(Activity.DOWNLOAD_SERVICE); 
    String[] contentParts = contentUri.getEncodedPath().split("/"); 
    Cursor q = downloadManager.query(new DownloadManager.Query().setFilterById(Integer.parseInt(contentParts[contentParts.length - 1]))); 
    if (q == null) { 
     // Download no longer exists 
     return null; 
    } 
    q.moveToFirst(); 
    return q.getString(q.getColumnIndex(DownloadManager.COLUMN_LOCAL_FILENAME)); 
} 

ma il cursore non restituisce tutte le righe (così q.getCount() == 0 e per questo l'ultima return dichiarazione genera un'eccezione). Inoltre, l'hack analizzando l'ID del file di download dall'URI sembra strano.

UPDATE: Ho anche provato:

input = getActivity().getContentResolver().openInputStream(contentUri); 

ma questo restituisce un errore che indica

Permesso Denial: lettura com.android.providers.downloads.DownloadProvider contenuti uri:// download/all_downloads/2334 da pid = 30950, uid = 10064 richiede android.permission.ACCESS_ALL_DOWNLOADS o grantUriPermission()

Chiaramente non riesco ad accedere ai download (poiché la mia app non li ha avviati - ha fatto il browser) tramite lo ContentProvider.

+0

btw il vostro primo approccio funziona allright per me, tornando DownloadManager.COLUMN_STATUS == STATUS_SUCCESSFUL e un URI valido nel colonna COLUMN_LOCAL_URI. – southerton

risposta

1

Ottenere il risolutore di contenuti è la cosa giusta. Non tutti gli URL dei contenuti saranno un file. Ad esempio, l'app Galleria ti fornirà uri che traducono in una chiamata di rete o in un file locale a seconda della fonte.

Anche se si arriva al percorso del file reale, probabilmente non è possibile leggerlo, a causa delle autorizzazioni sui file, anche se si può essere fortunati che si trovi su una memoria esterna. Hai provato ad aggiungere android.permission.ACCESS_ALL_DOWNLOADS alla tua app come suggerisce l'eccezione?That won't work, since the permission is at signature level :(

+0

Sì, mi aspetto di dover passare attraverso ContentResolver, ma con i problemi sopra descritti. E sì, '' è nel mio file AndroidManifest.xml, ma non sono nemmeno sicuro che tu debba chiedere questo permesso ... –

+0

Ho appena fatto una semplice app di test e che ha funzionato bene per me. L'eccezione implica che hai in qualche modo "perso" il permesso di lettura che ti è concesso se il file viene cliccato nell'app per download. – botteaap

5

Ecco cosa ha funzionato. Innanzitutto, non è possibile (e non si vuole) ottenere il percorso del file come indicato correttamente da botteaap. (. Credits a lui per me l'impostazione sulla strada giusta) invece si ottiene un permesso temporaneoautomaticamente per accedere al contenuto del file, usando:

InputStream input = getContentResolver().openInputStream(intent.getData()); 

Si può leggere questo InputStream come qualsiasi altro in Java. Sembra che non ci sia modo di ottenere il nome del file. Se hai bisogno di un file, scrivi prima il flusso di input in un file (temporaneo).

Il SecurityException viene rilasciato quando l'accesso temporaneo è stato revocato. Questo è accaduto per me su alcuni file che ho provato a leggere in modo errato prima e specificamente quando l'Intento è stato rilevato in onNewIntent di Acticity.

+1

È possibile ottenere il nome e la dimensione utilizzando un cursore, ma non l'intero URL. È una buona idea ottenere il nome, in modo da poter memorizzare il file temporaneo con lo stesso nome e l'estensione del file – jcesarmobile

+0

Hai trovato un modo per evitare il 'SecurityException' in' onNewIntent'? Sto avendo lo stesso problema e non riesco a capire cosa fare al riguardo. –

+0

@Jarett No, non specificamente tranne che ho cambiato la modalità di avvio dell'attività e non ho più questo problema. Forse è legato a singleInstance (io uso singleTop ora) poiché l'attività avrà sempre l'intento consegnato in onNewIntent, che è dove ho avuto il problema. Scusa non ho più informazioni –

2

Voglio solo aggiungere alla risposta di @erickok in quanto mi ci sono volute diverse ore per capirlo. Come dichiarato da @jcesarmobile, ti garantiamo solo il nome e la dimensione del file, non il percorso completo.

È possibile ottenere il nome e la dimensione come segue, e quindi salvare in un file temporaneo:

String filename = null; 
Long filesize = null; 
Cursor cursor = null; 
try { 
    cursor = this.getContentResolver().query(intent.getData(), new String[] { 
     OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE}, null, null, null); 
    if (cursor != null && cursor.moveToFirst()) { 
     filename = cursor.getString(0); 
     filesize = cursor.getLong(1); 
    } 
} finally { 
    if (cursor != null) 
     cursor.close(); 
} 
+0

Questo non è un nome di file, è un titolo assegnato al metodo setTitle di DownloadManager.Request. – southerton