Diferencia entre revisiones de «PDM Avanzado Accedendo á SD en Android 5.1»

De MediaWiki
Ir a la navegación Ir a la búsqueda
(Página creada con «==Introdución== * A partires da API 23 o acceso a SD considérase un permiso perigoso polo que temos que solicitar dentro da aplicación o permiso ao usuario. : Isto est...»)
 
Línea 10: Línea 10:
  
  
−
==Acceso 'tradicional'==
+
==Obtendo a información dos arquivos multimedia: Método 1==
  
 
:Nas versións anteriores de Android podíamos percorrer toda a tarxeta buscando os arquivos de tipo 'multimedia' e extraendo as súas propiedades (título, xénero,...).
 
:Nas versións anteriores de Android podíamos percorrer toda a tarxeta buscando os arquivos de tipo 'multimedia' e extraendo as súas propiedades (título, xénero,...).
Línea 65: Línea 65:
 
MediaMetadataRetriever mmr = new MediaMetadataRetriever();
 
MediaMetadataRetriever mmr = new MediaMetadataRetriever();
  
−
mmr.setDataSource(cancion.getAbsolutePath());
 
 
Cancion c= new Cancion();
 
Cancion c= new Cancion();
 
c.titulo=mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE);
 
c.titulo=mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE);
Línea 81: Línea 80:
  
  
 +
==Obtendo a información dos arquivos multimedia: Método 2==
  
 +
* Outra forma de acceder aos contidos multimedia tanto da tarxeta SD Interna como a SD Externa é a través da clase [MediaStore | http://developer.android.com/intl/es/reference/android/provider/MediaStore.html].
  
 +
* A forma de acceder é a seguinte:
  
 +
:* Determinamos o tipo de arquivo que queremos explorar:
 +
 +
:<syntaxhighlight lang="java" line enclose="div" highlight="" >
 +
Uri allsongsuri = MediaStore.Audio.Media.INTERNAL_CONTENT_URI;
 +
</syntaxhighlight>
 +
 +
:Neste caso estamos a buscar os arquivos de audio da tarxeta SD Interna.
 +
 +
:Podemos utilizar:
 +
::*MediaStore.Audio: Arquivos de audio.
 +
::*MediaStore.Files: Arquivos multimedia e non multimedia.
 +
::*MediaStore.Images: Arquivos de imaxe
 +
::*MediaStore.Video: Arquivos de vídeo.
 +
 +
:E podemos indicar a tarxeta externa coa constante: '''EXTERNAL_CONTENT_URI'''.
 +
 +
 +
:* Debemos de facer unha query buscando os arquivos que pertenzan a ese tipo. O resultado da query será un curso coas referencias aos arquivos:
 +
 +
:<syntaxhighlight lang="java" line enclose="div" highlight="1,4" >
 +
Cursor cursor;
 +
Uri allsongsuri = MediaStore.Audio.Media.INTERNAL_CONTENT_URI;
 +
 +
  cursor = getContentResolver().query(allsongsuri, null, null, null, "_id");
 +
</syntaxhighlight>
 +
 +
 +
:* Percorremos o listado de arquivos e obtemos a información multimedia:
 +
 +
:<syntaxhighlight lang="java" line enclose="div" highlight="1,4" >
 +
                    do {
 +
                        String nomeCancion = cursor
 +
                                .getString(cursor
 +
                                        .getColumnIndex(MediaStore.Audio.Media.DISPLAY_NAME));
 +
                        int idCancion = cursor.getInt(cursor
 +
                                .getColumnIndex(MediaStore.Audio.Media._ID));
 +
 +
                        String fullPath = cursor.getString(cursor
 +
                                .getColumnIndex(MediaStore.Audio.Media.DATA));
 +
 +
                        String nomeAlbum = cursor.getString(cursor
 +
                                .getColumnIndex(MediaStore.Audio.Media.ALBUM));
 +
 +
 +
                    } while (cursor.moveToNext());
 +
 +
</syntaxhighlight>
 +
 +
 +
: Podemos obter moita máis información multimedia nestes enlaces:
 +
 +
::* [http://developer.android.com/intl/es/reference/android/provider/MediaStore.Audio.AudioColumns.html | Información Multimedia ]
 +
 +
 +
:* Á hora de buscar o xénero xa se complica a cousa. A idea é de buscar por cada canción o/os xéneros aos que pertence.
 +
 +
 +
 +
 +
==Caso práctico==
 +
 +
Neste código imos ver un exemplo de como conseguir información multimedia:
 +
 +
:<syntaxhighlight lang="java" line enclose="div" highlight="1,4" >
 +
 +
 +
import android.Manifest;
 +
 +
import android.app.Activity;
 +
import android.content.pm.PackageManager;
 +
import android.database.Cursor;
 +
import android.net.Uri;
 +
import android.os.Build;
 +
import android.provider.MediaStore;
 +
import android.os.Bundle;
 +
import android.util.Log;
 +
import android.view.Menu;
 +
import android.view.MenuItem;
 +
import android.widget.Toast;
 +
 +
import java.util.List;
 +
 +
public class MainActivity extends Activity {
 +
 +
    private String[] STAR = { "*" };
 +
 +
    // Usado por si necesitamos diferentes permisos, para identificar cual de ellos es
 +
    private final int CODIGO_IDENTIFICADOR=1;
 +
 +
 +
    public void pedirPermiso(){
 +
 +
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
 +
            requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, CODIGO_IDENTIFICADOR);
 +
        }
 +
        else
 +
            listarCancions();
 +
 +
 +
    }
 +
 +
    @Override
 +
    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
 +
 +
        switch (requestCode) {
 +
            case CODIGO_IDENTIFICADOR: {
 +
                // Se o usuario premeou o boton de cancelar o array volve cun null
 +
                if (grantResults.length > 0
 +
                        && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
 +
                    // PERMISO CONCEDIDO
 +
                    listarCancions();
 +
                } else {
 +
                    // PERMISO DENEGADO
 +
                    Toast.makeText(this, "É NECESARIO O PERMISO PARA CHAMAR POR TELÉFONO", Toast.LENGTH_LONG).show();
 +
                }
 +
                return;
 +
            }
 +
 +
            // Comprobamos os outros permisos
 +
 +
        }
 +
    }
 +
 +
    }
 +
    public void listarCancions()
 +
    {
 +
 +
        Cursor cursor;
 +
        Uri allsongsuri = MediaStore.Audio.Media.INTERNAL_CONTENT_URI;
 +
 +
        if (isSdPresent()) {
 +
 +
            cursor = getContentResolver().query(allsongsuri, null, null, null, "_id");
 +
            if (cursor != null) {
 +
                if (cursor.moveToFirst()) {
 +
                    do {
 +
                        String songname = cursor
 +
                                .getString(cursor
 +
                                        .getColumnIndex(MediaStore.Audio.Media.DISPLAY_NAME));
 +
                        int song_id = cursor.getInt(cursor
 +
                                .getColumnIndex(MediaStore.Audio.Media._ID));
 +
 +
                        String fullpath = cursor.getString(cursor
 +
                                .getColumnIndex(MediaStore.Audio.Media.DATA));
 +
 +
                        String albumname = cursor.getString(cursor
 +
                                .getColumnIndex(MediaStore.Audio.Media.ALBUM));
 +
 +
 +
                        Uri uri = MediaStore.Audio.Genres.getContentUriForAudioId("external", song_id);
 +
 +
                        String[] genresProjection = {
 +
                                MediaStore.Audio.Genres.NAME,
 +
                                MediaStore.Audio.Genres._ID
 +
                        };
 +
                        Cursor genresCursor;
 +
                        String info="";
 +
                        genresCursor = getContentResolver().query(uri,
 +
                                genresProjection, null, null, null);
 +
                        int genre_column_index = genresCursor.getColumnIndexOrThrow(MediaStore.Audio.Genres.NAME);
 +
 +
                        if (genresCursor.moveToFirst()) {
 +
                            info += "Genres: ";
 +
                            do {
 +
                                info += genresCursor.getString(genre_column_index) + " ";
 +
                            } while (genresCursor.moveToNext());
 +
                        }
 +
                        Log.i("INFO", songname);
 +
                        Log.i("INFO", albumname);
 +
                        Log.i("INFO", info);
 +
 +
                    } while (cursor.moveToNext());
 +
                }
 +
                cursor.close();
 +
            }
 +
        }
 +
    }
 +
 +
 +
    public static boolean isSdPresent()
 +
    {
 +
        return android.os.Environment.getExternalStorageState().equals(
 +
                android.os.Environment.MEDIA_MOUNTED);
 +
    }
 +
 +
    @Override
 +
    protected void onCreate(Bundle savedInstanceState) {
 +
        super.onCreate(savedInstanceState);
 +
        setContentView(R.layout.activity_main);
 +
 +
 +
        pedirPermiso();
 +
 +
    }
 +
 +
    @Override
 +
    public boolean onCreateOptionsMenu(Menu menu) {
 +
        // Inflate the menu; this adds items to the action bar if it is present.
 +
        getMenuInflater().inflate(R.menu.menu_main, menu);
 +
        return true;
 +
    }
 +
 +
    @Override
 +
    public boolean onOptionsItemSelected(MenuItem item) {
 +
        // Handle action bar item clicks here. The action bar will
 +
        // automatically handle clicks on the Home/Up button, so long
 +
        // as you specify a parent activity in AndroidManifest.xml.
 +
        int id = item.getItemId();
 +
 +
        //noinspection SimplifiableIfStatement
 +
        if (id == R.id.action_settings) {
 +
            return true;
 +
        }
 +
 +
        return super.onOptionsItemSelected(item);
 +
    }
 +
}
 +
 +
 +
 +
 +
</syntaxhighlight>
  
  

Revisión del 00:13 23 nov 2015

Introdución

  • A partires da API 23 o acceso a SD considérase un permiso perigoso polo que temos que solicitar dentro da aplicación o permiso ao usuario.
Isto está explicado no enlace seguinte: [Permisos especiais Android 5.0 | http://mediawiki.cifprodolfoucha.es/index.php?title=PDM_Avanzado_Permisos_AndroidManifiest.xml]. Teremos que solicitar o permiso Manifest.permission.READ_EXTERNAL_STORAGE se queremos acceder a tarxeta SD Externa e temos no AndroidManifiest un target=23 e estamos a probar cun dispositivo cunha API 23.


  • Pode suceder que queiramos facer unha aplicación que teña acceso a os arquivos multimedia da nosa tarxeta SD.
  • Imos ver dúas formas de facer isto, tendo en conta que o acceso á SD Externa para buscar arquivos pode non funcionar en versións superiores á API 21.


Obtendo a información dos arquivos multimedia: Método 1

Nas versións anteriores de Android podíamos percorrer toda a tarxeta buscando os arquivos de tipo 'multimedia' e extraendo as súas propiedades (título, xénero,...).
Un exemplo de código:


Clase onde gardaríamos as propiedades:

 1 public class Cancion {
 2 
 3 	public int id;
 4 	public String titulo;
 5 	public String artista;
 6 	public String album;
 7 	public String genero;
 8 	public String year;// Tiene que ser un String porque en algunas canciones no esta en formato de numero
 9 	public String duracion;
10 	public String numeroPista;
11 	public byte[] imagen;
12 	public String fechaAdd;
13 	public String ruta;
14 	
15 	public Cancion(){
16 		
17 	}
18 	public Cancion(int id,String titulo,String artista,String album,String genero,
19 			String duracion,String year,byte[] imagen,String fechaAdd,String numeroPista,String ruta){
20 		
21 		this.id=id;
22 		this.titulo=titulo;
23 		this.artista=artista;
24 		this.album=album;
25 		this.genero=genero;
26 		this.year=year;
27 		this.duracion=duracion;
28 		this.numeroPista=numeroPista;
29 		this.fechaAdd=fechaAdd;
30 		this.ruta=ruta;
31 	}
32 	
33 }



Método que devolve un obxecto da clase Cancion cos datos obtidos a partires dun File:

 1 	public static Cancion crearCanciones(File cancion){
 2 		
 3 		MediaMetadataRetriever mmr = new MediaMetadataRetriever();
 4 
 5 			Cancion c= new Cancion();
 6 			c.titulo=mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE);
 7 			c.artista=mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST);
 8 			c.album=mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUM);
 9 			c.genero=mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_GENRE);
10 			c.numeroPista=mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_CD_TRACK_NUMBER);			
11 			c.duracion=String.format("%1$TM:%1$TS",Long.parseLong(mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)));
12 			c.year=mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_YEAR);
13 			c.ruta=cancion.getAbsolutePath();	
14 		return c;
15 	}


Obtendo a información dos arquivos multimedia: Método 2

  • A forma de acceder é a seguinte:
  • Determinamos o tipo de arquivo que queremos explorar:
1 Uri allsongsuri = MediaStore.Audio.Media.INTERNAL_CONTENT_URI;
Neste caso estamos a buscar os arquivos de audio da tarxeta SD Interna.
Podemos utilizar:
  • MediaStore.Audio: Arquivos de audio.
  • MediaStore.Files: Arquivos multimedia e non multimedia.
  • MediaStore.Images: Arquivos de imaxe
  • MediaStore.Video: Arquivos de vídeo.
E podemos indicar a tarxeta externa coa constante: EXTERNAL_CONTENT_URI.


  • Debemos de facer unha query buscando os arquivos que pertenzan a ese tipo. O resultado da query será un curso coas referencias aos arquivos:
1  Cursor cursor;
2  Uri allsongsuri = MediaStore.Audio.Media.INTERNAL_CONTENT_URI;
3 
4   cursor = getContentResolver().query(allsongsuri, null, null, null, "_id");


  • Percorremos o listado de arquivos e obtemos a información multimedia:
 1                     do {
 2                         String nomeCancion = cursor
 3                                 .getString(cursor
 4                                         .getColumnIndex(MediaStore.Audio.Media.DISPLAY_NAME));
 5                         int idCancion = cursor.getInt(cursor
 6                                 .getColumnIndex(MediaStore.Audio.Media._ID));
 7 
 8                         String fullPath = cursor.getString(cursor
 9                                 .getColumnIndex(MediaStore.Audio.Media.DATA));
10 
11                         String nomeAlbum = cursor.getString(cursor
12                                 .getColumnIndex(MediaStore.Audio.Media.ALBUM));
13 
14 
15                     } while (cursor.moveToNext());


Podemos obter moita máis información multimedia nestes enlaces:


  • Á hora de buscar o xénero xa se complica a cousa. A idea é de buscar por cada canción o/os xéneros aos que pertence.



Caso práctico

Neste código imos ver un exemplo de como conseguir información multimedia:

  1 import android.Manifest;
  2 
  3 import android.app.Activity;
  4 import android.content.pm.PackageManager;
  5 import android.database.Cursor;
  6 import android.net.Uri;
  7 import android.os.Build;
  8 import android.provider.MediaStore;
  9 import android.os.Bundle;
 10 import android.util.Log;
 11 import android.view.Menu;
 12 import android.view.MenuItem;
 13 import android.widget.Toast;
 14 
 15 import java.util.List;
 16 
 17 public class MainActivity extends Activity {
 18 
 19     private String[] STAR = { "*" };
 20 
 21     // Usado por si necesitamos diferentes permisos, para identificar cual de ellos es
 22     private final int CODIGO_IDENTIFICADOR=1;
 23 
 24 
 25     public void pedirPermiso(){
 26 
 27         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
 28             requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, CODIGO_IDENTIFICADOR);
 29         }
 30         else
 31             listarCancions();
 32 
 33 
 34     }
 35 
 36     @Override
 37     public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
 38 
 39         switch (requestCode) {
 40             case CODIGO_IDENTIFICADOR: {
 41                 // Se o usuario premeou o boton de cancelar o array volve cun null
 42                 if (grantResults.length > 0
 43                         && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
 44                     // PERMISO CONCEDIDO
 45                     listarCancions();
 46                 } else {
 47                     // PERMISO DENEGADO
 48                     Toast.makeText(this, "É NECESARIO O PERMISO PARA CHAMAR POR TELÉFONO", Toast.LENGTH_LONG).show();
 49                 }
 50                 return;
 51             }
 52 
 53             // Comprobamos os outros permisos
 54 
 55         }
 56     }
 57 
 58     }
 59     public void listarCancions()
 60     {
 61 
 62         Cursor cursor;
 63         Uri allsongsuri = MediaStore.Audio.Media.INTERNAL_CONTENT_URI;
 64 
 65         if (isSdPresent()) {
 66 
 67             cursor = getContentResolver().query(allsongsuri, null, null, null, "_id");
 68             if (cursor != null) {
 69                 if (cursor.moveToFirst()) {
 70                     do {
 71                         String songname = cursor
 72                                 .getString(cursor
 73                                         .getColumnIndex(MediaStore.Audio.Media.DISPLAY_NAME));
 74                         int song_id = cursor.getInt(cursor
 75                                 .getColumnIndex(MediaStore.Audio.Media._ID));
 76 
 77                         String fullpath = cursor.getString(cursor
 78                                 .getColumnIndex(MediaStore.Audio.Media.DATA));
 79 
 80                         String albumname = cursor.getString(cursor
 81                                 .getColumnIndex(MediaStore.Audio.Media.ALBUM));
 82 
 83 
 84                         Uri uri = MediaStore.Audio.Genres.getContentUriForAudioId("external", song_id);
 85 
 86                         String[] genresProjection = {
 87                                 MediaStore.Audio.Genres.NAME,
 88                                 MediaStore.Audio.Genres._ID
 89                         };
 90                         Cursor genresCursor;
 91                         String info="";
 92                         genresCursor = getContentResolver().query(uri,
 93                                 genresProjection, null, null, null);
 94                         int genre_column_index = genresCursor.getColumnIndexOrThrow(MediaStore.Audio.Genres.NAME);
 95 
 96                         if (genresCursor.moveToFirst()) {
 97                             info += "Genres: ";
 98                             do {
 99                                 info += genresCursor.getString(genre_column_index) + " ";
100                             } while (genresCursor.moveToNext());
101                         }
102                         Log.i("INFO", songname);
103                         Log.i("INFO", albumname);
104                         Log.i("INFO", info);
105 
106                     } while (cursor.moveToNext());
107                 }
108                 cursor.close();
109             }
110         }
111     }
112 
113 
114     public static boolean isSdPresent()
115     {
116         return android.os.Environment.getExternalStorageState().equals(
117                 android.os.Environment.MEDIA_MOUNTED);
118     }
119 
120     @Override
121     protected void onCreate(Bundle savedInstanceState) {
122         super.onCreate(savedInstanceState);
123         setContentView(R.layout.activity_main);
124 
125 
126         pedirPermiso();
127 
128     }
129 
130     @Override
131     public boolean onCreateOptionsMenu(Menu menu) {
132         // Inflate the menu; this adds items to the action bar if it is present.
133         getMenuInflater().inflate(R.menu.menu_main, menu);
134         return true;
135     }
136 
137     @Override
138     public boolean onOptionsItemSelected(MenuItem item) {
139         // Handle action bar item clicks here. The action bar will
140         // automatically handle clicks on the Home/Up button, so long
141         // as you specify a parent activity in AndroidManifest.xml.
142         int id = item.getItemId();
143 
144         //noinspection SimplifiableIfStatement
145         if (id == R.id.action_settings) {
146             return true;
147         }
148 
149         return super.onOptionsItemSelected(item);
150     }
151 }





-- Ángel D. Fernández González -- (2015).