Uno de mis requisitos en JustPlay (de hecho, el fundamental), es poder reproducir a partir de archivos sueltos o directorios.
Por tanto, necesitaré un explorador de archivos, aunque sea muy básico, que permita ver los archivos en la memoria del dispositivo y añadirlos a una lista de reproducción. Gráficamente, la interacción entre las actividades sería así. En general la devolución del parámetro no tendrá mayor problema, ya que se puede hacer a través del intent de vuelta.
Para crear el explorador de archivos voy a seguir este tutorial, por supuesto añadiendo cosas de mi cosecha según me vaya pareciendo.
Creación de CrankExplorer
En primer lugar creo la activity tal cual heredando de CrankActivity y le añado la implementación por defecto de todos los métodos del ciclo de vida.
Ahora la declaro en el AndroidManifest:
<activity android:name=".FileExplorer" android:label="@string/explorer_name"/>
Para arrancarla, creo un botón en MediaPlayer:
<Button
android:id="@+id/buttonOpenExplorer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/open_explorer"
android:onClick="openCrankExplorer" />
Y el listener:
public void openCrankExplorer(View v) {
Intent openCrankExplorer = new Intent(this, CrankExplorer.class);
startActivityForResult(openCrankExplorer, REQUEST_CODE);
}
Con esto ya puedo llamar a FileExplorer desde MediaPlayer.
Ahora toca implementar FileExplorer, en general la implementación seguirá estas líneas:
- Se mostrarán todos los archivos y directorios que se puedan leer.
- Si se hace click en un directorio se abrirá.
- Si se hace click en un archivo, se abrirá un diálogo de confirmación para añadirlo a la lista de reproducción.
- Si se deja presionado un directorio se abrirá un menú contextual para añadir todo su contenido a la lista de reproducción.
Al lío, siguiendo lo que comentan, hago un layout para los archivos, le voy a llamar file_row.xml y a continuación creo el layout de FileExplorer, crankexplorer.xml. No tiene mucha historia ya que es una lista y punto.
En cuanto a la actividad, lo primero que hago es filtrar los archivos mediante un FilenameFilter, para que solo muestre aquellos directorios y archivos que sean legibles y si es un archivo, que además termine en mp3 u ogg.
Añado un onListItemClick y si es un directorio se invocará a getDir sobre él, mientras que si es un archivo, se mostrará un diálogo que permitirá dos acciones:
- Añadir el archivo a la lista de reproducción.
- Cancelar
Por último, para devolver la canción a MediaPlayer, creo un método finish().
Para ir acabando, falta el menú contextual que me permita seleccionar un directorio para añadir (junto con todos los archivos contenidos en él y sus subdirectorios). Primero creo el layout del menu y lo llamo crankexplorer_context.xml a continuación en el onCreate, registro la lista para el menú contextual:
registerForContextMenu(getListView());
Después tengo que crear dos métodos del ciclo de vida, el primero, la creación del menú:
@Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
menu.setHeaderTitle(R.string.directory_contextual_title);
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.crankexplorer_context, menu);
}
Y el segundo, la acción a ejecutar cuando se selecciona:
@Override
public boolean onContextItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.addDirectoryItem:
AdapterContextMenuInfo info = (AdapterContextMenuInfo) item
.getMenuInfo();
this.selected = new File(this.path.get((int) info.id));
if (this.selected.isDirectory()) {
finish();
}
return true;
default:
return super.onContextItemSelected(item);
}
}
Para acabar, implemento el método finish() para devolver bien la canción seleccionada, bien todas las canciones:
@Override
public void finish() {
Intent data = new Intent();
if (this.selected != null) {
if (this.selected.isFile()) {
data.putExtra("selectedFile", this.selected);
} else if (this.selected.isDirectory()) {
List<File> filesInDirectory = this.explodeDir(this.selected);
data.putExtra("selectedFiles",
(ArrayList<File>) filesInDirectory);
}
}
setResult(RESULT_OK, data);
super.finish();
}
Y en MediaPlayer creo un onActivityResult que procese la vuelta desde FileExplorer:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (data.hasExtra("selectedFile")) {
this.playlist.add((File) data.getExtras().get("selectedFile"));
this.renderPlaylist();
} else if (data.hasExtra("selectedFiles")) {
List<File> fileList = (List<File>) data.getExtras().get(
"selectedFiles");
this.playlist.addAll(fileList);
this.renderPlaylist();
}
}
TODO
Pues ya solo queda:
- Hacer el bind del service en MediaPlayer
- Reproducir con un MediaPlayer en el thread.
Código
Sigue en GitHub