package com.tid.examples.observer;
import java.util.HashSet;
import java.util.Set;
import android.content.Context;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Handler;
import android.provider.MediaStore;
import android.util.Log;
/**
* El MediaObserver encapsula diferentes observers (Image, Audio y Video)
* para poder diferenciar donde se estan produciendo los cambios en el ContentProvider
*
* Cada Provider llama a la funcion correspondiente en su metodo 'onChange' para hacer
* el trabajo que queramos
*
* IMPORTANTE: el metodo onChange solo devuelve que ha habido un cambio en el provider,
* pero no podemos saber si es un elemento creado, borrado, etc.
* Nos tenemos que hacer cargo de esa logica nosotros mismos, como se ve en estos ejemplos.
*
*/
public class MediaObserver {
private static final String TAG = "MediaObserver";
public static final Uri IMAGES_CONTENT_URI = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
public static final Uri AUDIO_CONTENT_URI = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
public static final Uri VIDEOS_CONTENT_URI = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
public static String[] ID_PROJECTION = {MediaStore.MediaColumns._ID};
private Context mContext;
private Handler mHandler;
//Observers
private ImageObserver mImageObserver;
private AudioObserver mAudioObserver;
private VideoObserver mVideoObserver;
//Fake web service
private FakeWebService mService;
public MediaObserver(Context context, Handler handler) {
mContext = context;
mHandler = handler;
mImageObserver = new ImageObserver(mHandler);
mAudioObserver = new AudioObserver(mHandler);
mVideoObserver = new VideoObserver(mHandler);
mService = new FakeWebService(context);
}
private class ImageObserver extends ContentObserver {
public ImageObserver(Handler handler) {
super(handler);
}
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
Log.i(TAG, "Notification in ImageObserver");
updateImages();
}
}
private class AudioObserver extends ContentObserver {
public AudioObserver(Handler handler) {
super(handler);
}
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
Log.i(TAG, "Notification in AudioObserver");
updateAudio();
}
}
private class VideoObserver extends ContentObserver {
public VideoObserver(Handler handler) {
super(handler);
}
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
Log.i(TAG, "Notification in VideoObserver");
updateVideos();
}
}
public void registerObserver(){
mContext.getContentResolver().registerContentObserver(IMAGES_CONTENT_URI, true, mImageObserver);
mContext.getContentResolver().registerContentObserver(AUDIO_CONTENT_URI, true, mAudioObserver);
mContext.getContentResolver().registerContentObserver(VIDEOS_CONTENT_URI, true, mVideoObserver);
Log.i(TAG, "Registering observer for: " + IMAGES_CONTENT_URI);
Log.i(TAG, "Registering observer for: " + AUDIO_CONTENT_URI);
Log.i(TAG, "Registering observer for: " + VIDEOS_CONTENT_URI);
}
public void unregisterObserver(){
mContext.getContentResolver().unregisterContentObserver(mImageObserver);
mContext.getContentResolver().unregisterContentObserver(mAudioObserver);
mContext.getContentResolver().unregisterContentObserver(mVideoObserver);
}
private void updateImages(){
Cursor c = mContext.getContentResolver().
query(IMAGES_CONTENT_URI, ID_PROJECTION, null, null, null);
int remoteElementsNum = mService.getImagesCount();
//Comparamos el numero de elementos locales y remotos
//Si es distinto hay que sincronizar
if (c.getCount() != remoteElementsNum){
//Almacenamos los ids en un set
Set<Long> ids = new HashSet<Long>();
if (c.moveToFirst()){
do {
long id = c.getLong(c.getColumnIndex(MediaStore.MediaColumns._ID));
ids.add(id);
} while (c.moveToNext());
}
if (c != null)
c.close();
//Obtenemos los elementos creados y borrados
Set<Long> newElements = getNewElements(ids, mService.getImageIds());
Set<Long> deletedElements = getDeletedElements(ids, mService.getImageIds());
Log.i(TAG, "Elementos a crear: " + newElements);
Log.i(TAG, "Elementos a borrar: " + deletedElements);
//Llamamos al FakeWebService para realizar las operaciones convenientes
mService.addImages(newElements);
mService.deleteImages(deletedElements);
}
}
private void updateAudio(){
Cursor c = mContext.getContentResolver().
query(AUDIO_CONTENT_URI, ID_PROJECTION, null, null, null);
int remoteElementsNum = mService.getAudioCount();
//Comparamos el numero de elementos locales y remotos
//Si es distinto hay que sincronizar
if (c.getCount() != remoteElementsNum){
//Almacenamos los ids en un set
Set<Long> ids = new HashSet<Long>();
if (c.moveToFirst()){
do {
long id = c.getLong(c.getColumnIndex(MediaStore.MediaColumns._ID));
ids.add(id);
} while (c.moveToNext());
}
if (c != null)
c.close();
//Obtenemos los elementos creados y borrados
Set<Long> newElements = getNewElements(ids, mService.getAudioIds());
Set<Long> deletedElements = getDeletedElements(ids, mService.getAudioIds());
Log.i(TAG, "Elementos a crear: " + newElements);
Log.i(TAG, "Elementos a borrar: " + deletedElements);
//Llamamos al FakeWebService para realizar las operaciones convenientes
mService.addAudios(newElements);
mService.deleteAudios(deletedElements);
}
}
private void updateVideos(){
Cursor c = mContext.getContentResolver().
query(VIDEOS_CONTENT_URI, ID_PROJECTION, null, null, null);
int remoteElementsNum = mService.getVideoCount();
//Comparamos el numero de elementos locales y remotos
//Si es distinto hay que sincronizar
if (c.getCount() != remoteElementsNum){
//Almacenamos los ids en un set
Set<Long> ids = new HashSet<Long>();
if (c.moveToFirst()){
do {
long id = c.getLong(c.getColumnIndex(MediaStore.MediaColumns._ID));
ids.add(id);
} while (c.moveToNext());
}
if (c != null)
c.close();
//Obtenemos los elementos creados y borrados
Set<Long> newElements = getNewElements(ids, mService.getVideoIds());
Set<Long> deletedElements = getDeletedElements(ids, mService.getVideoIds());
Log.i(TAG, "Elementos a crear: " + newElements);
Log.i(TAG, "Elementos a borrar: " + deletedElements);
//Llamamos al FakeWebService para realizar las operaciones convenientes
mService.addVideos(newElements);
mService.deleteVideos(deletedElements);
}
}
/**
* Compara a partir de las dos primeras listas los elementos locales
* y remotos y devuelve un set con los elementos nuevos
*
* @param localList ids locales
* @param remoteList ids remotos
* @returns elementos locales creados (para incluir en remoto)
*/
private Set<Long> getNewElements(Set<Long> localList, Set<Long> remoteList){
Set<Long> newElements = new HashSet<Long>(localList);
newElements.removeAll(remoteList);
return newElements;
}
/**
* Compara a partir de las dos primeras listas los elementos locales
* y remotos y devuelve un set con los elementos borrados
*
* @param localList ids locales
* @param remoteList ids remotos
* @returns elementos locales borrados (para borrar en remoto)
*/
private Set<Long> getDeletedElements(Set<Long> localList, Set<Long> remoteList){
Set<Long> deleted = new HashSet<Long>(remoteList);
deleted.removeAll(localList);
return deleted;
}
}