/******************************************************************************* * Code contributed to the webinos project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright 2011 Telecom Italia SpA * ******************************************************************************/ package org.webinos.android.impl; import java.io.File; import java.util.ArrayList; import java.util.Date; import java.util.List; import org.meshpoint.anode.AndroidContext; import org.meshpoint.anode.bridge.Env; import org.meshpoint.anode.module.IModule; import org.meshpoint.anode.module.IModuleContext; import org.webinos.api.ErrorCallback; import org.webinos.api.PendingOperation; import org.webinos.api.gallery.GalleryErrorCB; import org.webinos.api.gallery.GalleryFindCB; import org.webinos.api.gallery.GalleryFindOptions; import org.webinos.api.gallery.GalleryInfo; import org.webinos.api.gallery.GalleryInfoCB; import org.webinos.api.gallery.GalleryManager; import org.webinos.api.gallery.GalleryError; import org.webinos.api.gallery.MediaObject; import android.content.Context; import android.util.Log; import android.media.MediaMetadataRetriever; import android.media.ExifInterface; import android.webkit.MimeTypeMap; public class GalleryImpl extends GalleryManager implements IModule { private Context androidContext; private boolean searchInProgress; private static final String LABEL = "org.webinos.android.impl.GalleryImpl"; private static final String[] gallerySearchPaths = { "/sdcard" }; private static final String[] galleryExcludePaths = { "/sdcard/widget" }; //TODO automatically retrieve the supported mimetypes... private static final String[] supportedMimetypes = { "image/png", "image/jpeg", "image/gif", "audio/mpeg", "video/3gpp" }; /***************************** * GalleryManager methods *****************************/ @Override public PendingOperation find(String[] fields, GalleryFindCB successCB, GalleryErrorCB errorCB, GalleryFindOptions options) { Log.v(LABEL, "find"); GalleryFinder galleryFinder = new GalleryFinder(successCB, errorCB); Thread t = new Thread(galleryFinder); t.start(); return new GalleryPendingOperation(t, galleryFinder); } @Override public PendingOperation getGalleries(GalleryInfoCB successCB, GalleryErrorCB errorCB) { // TODO Auto-generated method stub return null; } /***************************** * IModule methods *****************************/ @Override public Object startModule(IModuleContext ctx) { androidContext = ((AndroidContext)ctx).getAndroidContext(); setSearchInProgress(false); return this; } @Override public void stopModule() { } private synchronized boolean getSearchInProgress() { return searchInProgress; } private synchronized void setSearchInProgress(boolean val) { searchInProgress = val; } class GalleryFinder implements GalleryRunnable { private Env env = Env.getCurrent(); private GalleryFindCB successCallback; private GalleryErrorCB errorCallback; private boolean stopped; private GalleryFinder(GalleryFindCB successCB, GalleryErrorCB errorCB) { this.successCallback = successCB; this.errorCallback = errorCB; } public synchronized boolean isStopped() { return stopped; } public synchronized void stop() { stopped = true; } private boolean searchGallery(int index) { return true; } private boolean isMediaFile(File file) { String fileName = file.getName(); if(fileName.lastIndexOf(".")>0) { String extension = fileName.substring(fileName.lastIndexOf(".")); String mimetype = MimeTypeMap.getSingleton().getMimeTypeFromExtension(MimeTypeMap.getFileExtensionFromUrl(extension)); for (String supportedMimetype: supportedMimetypes){ if(supportedMimetype == mimetype) { Log.v(LABEL, "File "+fileName+", mimetype "+mimetype); return true; } } } return false; } private MediaObject getMetadata (File file) { MediaObject result = new MediaObject(); result.id = 0; //TODO implement result.gallery = null; //TODO implement result.locator = "file://"+file.getAbsolutePath(); //TODO what should this be? MediaMetadataRetriever retriever = new MediaMetadataRetriever(); try { retriever.setDataSource(file.getAbsolutePath()); Log.v(LABEL, "filename is "+result.locator); result.title = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE); Log.v(LABEL, "title is "+result.title); result.language = null; //TODO not available? result.contributor = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST); result.Creator = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_AUTHOR); String dateTmp = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DATE); Log.v(LABEL, "date is "+dateTmp); result.CreateDate = null; //TODO implement - available DATE and YEAR result.location = null; //TODO not available? result.description = null; //TODO not available? result.keyword = null; //TODO not available? result.genre = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_GENRE); result.rating = null; //TODO not available? result.relation = null; //TODO ??? result.collection = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUM); result.copyright = null; //TODO not available? result.policy = null; //TODO not available? result.publisher = null; //TODO not available? result.targetAudience = null; //TODO not available? result.fragment = null; //TODO not available? result.namedFragment = null; //TODO not available? result.frameSize = null; //TODO not available? result.compression = null; //TODO not available? result.duration = Integer.parseInt(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)); result.format = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_MIMETYPE); //TODO implement result.samplingRate = null; //TODO not available? result.framerate = null; //TODO not available? result.averageBitRate = null; //TODO not available? result.numTracks = Integer.parseInt(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS)); } catch(IllegalArgumentException e) { Log.v(LABEL, "Error in processing file metadata (IllegalArgumentException)"); } catch(Exception e) { Log.v(LABEL, "Error in processing file metadata "+e.getMessage()); try { ExifInterface exifRetriever = new ExifInterface(file.getAbsolutePath()); result.title = null; //TODO not available? result.language = null; //TODO not available? result.contributor = null; //TODO not available? result.Creator = null; //TODO not available? String dateTmp = exifRetriever.getAttribute(ExifInterface.TAG_DATETIME); Log.v(LABEL, "date is "+dateTmp); result.CreateDate = null; result.location = null; //TODO not available? result.description = null; //TODO not available? result.keyword = null; //TODO not available? result.genre = null; //TODO not available? result.rating = null; //TODO not available? result.relation = null; //TODO not available? result.collection = null; //TODO not available? result.copyright = null; //TODO not available? result.policy = null; //TODO not available? result.publisher = null; //TODO not available? result.targetAudience = null; //TODO not available? result.fragment = null; //TODO not available? result.namedFragment = null; //TODO not available? result.frameSize = Integer.getInteger(exifRetriever.getAttribute(ExifInterface.TAG_IMAGE_LENGTH)); //TODO no sense: width, heigth, ??? result.compression = null; //TODO not available? result.duration = null; //TODO not available? result.format = null; //TODO not available? result.samplingRate = null; //TODO not available? result.framerate = null; //TODO not available? result.averageBitRate = null; //TODO not available? result.numTracks = null; //TODO not available? } catch(Exception e1) { Log.v(LABEL, "Error in processing file metadata "+e1.getMessage()); } } retriever.release(); return result; } private List<MediaObject> searchMediaFiles(File dir, List<MediaObject> inList) { //Log.v(LABEL, "searchMediaFiles - dir "+dir.getAbsolutePath()); List<MediaObject> result = inList; try { File[] dirFiles = dir.listFiles(); for(String excludeDir: galleryExcludePaths) { if(dir.getAbsolutePath().indexOf(excludeDir) != -1) { Log.v(LABEL, "EXCLUDE!"); return result; } } for(int j=0; j<dirFiles.length; j++) { //Log.v(LABEL, "searchMediaFiles - found "+dirFiles[j].getAbsolutePath()); if(!dirFiles[j].isHidden()) { if(dirFiles[j].isDirectory()) { result = searchMediaFiles(dirFiles[j], result); } else if(isMediaFile(dirFiles[j])) { //Log.v(LABEL, "searchMediaFiles - extracting metadata"); result.add(getMetadata(dirFiles[j])); } } } } catch(Exception e) { Log.v(LABEL, "searchMediaFiles exception "+e.getMessage()); } return result; } public void run() { try { Log.v(LABEL, "GalleryFinder run"); Env.setEnv(env); boolean busy = false; Log.v(LABEL, "GalleryFinder run - 01"); synchronized(this) { busy = getSearchInProgress(); setSearchInProgress(true); } Log.v(LABEL, "GalleryFinder run - 02"); if(busy){ GalleryError err = new GalleryError(); err.code = GalleryError.PENDING_OPERATION_ERROR; errorCallback.onError(err); return; } Log.v(LABEL, "GalleryFinder run - 03"); //perform search List<MediaObject> result = new ArrayList<MediaObject>(); for(String dirName: gallerySearchPaths) { File rootDir = new File(dirName); result = searchMediaFiles(rootDir, result); } Log.v(LABEL, "GalleryFinder run - 06 - "+result.size()+" results found"); successCallback.onSuccess(result.toArray(new MediaObject[result.size()])); Log.v(LABEL, "GalleryFinder run - 08"); setSearchInProgress(false); Log.v(LABEL, "GalleryFinder run - 09"); } catch(Exception e) { Log.v(LABEL, "GalleryFinder run - exception "+e.getMessage()); } } } } abstract interface GalleryRunnable extends Runnable { public abstract void stop(); public abstract boolean isStopped(); } class GalleryPendingOperation extends PendingOperation { private Thread t=null; private GalleryRunnable r=null; public GalleryPendingOperation(Thread t, GalleryRunnable r) { this.t = t; this.r = r; } public void cancel() { if(t!=null) { //TODO is this interrupt needed??? t.interrupt(); if(r!=null) r.stop(); } } }