package de.bsd.zwitscher.helper;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import android.graphics.*;
import de.bsd.zwitscher.PicHelperState;
import twitter4j.User;
import android.os.Environment;
import android.util.Log;
/**
* Helper class that deals with handling of pictures and storing
* them on local file system.
*/
public class PicHelper {
private static final String APP_BASE_DIR = "/Android/data/de.bsd.zwitscher/";
private String externalStorageState;
public PicHelper() {
externalStorageState = Environment.getExternalStorageState();
}
private static final long ONE_DAY = 24 * 60 * 60 * 1000L;
/**
* Load the user picture for the passed user.
* If this is on file system, it is checked if it has changed on the server.
* If it is not yet on filesystem, it is fetched from remote and stored locally.
* @param user User for which to obtain the picture
* @return Bitmap of the picture or null if loading failed.
*/
public Bitmap fetchUserPic(User user) {
if (user==null)
return null;
String tmp = user.getProfileImageURL();
URL imageUrl;
try {
imageUrl = new URL(tmp);
} catch (MalformedURLException e) {
Log.w("PicHelper","Got bad picture url for user " + user.getScreenName() + ": " + e.getMessage());
return null;
}
String username = user.getScreenName();
// Log.i("fetchUserPic","Looking for pic of user '" + username + "' from '" + imageUrl.toString() + "'");
boolean found = false;
// TODO use v8 methods when we require v8 in the manifest. Is probably too early yet.
try {
if (externalStorageState.equals(Environment.MEDIA_MOUNTED)) {
File iconFile = getPictureFileForUser(username);
if (iconFile!=null && iconFile.exists() && iconFile.lastModified() > System.currentTimeMillis() - ONE_DAY)
found = true;
}
if (found) {
// Log.i("fetchUserPic","Picture was on file system, returning it");
return getBitMapForScreenNameFromFile(username);
}
}
catch (Exception ioe) {
Log.w("PicHelper", ioe.getMessage());
}
// Log.i("fetchUserPic","found=" + found);
// Not found - fetch from remote and store it locally
if (!found) {
// See if there is already another thread syncing. If
// so, wait a while to see if it was successful
// and then return the data from the file system
if (PicHelperState.getInstance().isSyncing(username)) {
int rounds = 10;
while (rounds>0) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace(); // TODO: Customise this generated block
}
if (!PicHelperState.getInstance().isSyncing(username)) {
return getBitMapForScreenNameFromFile(username);
}
rounds--;
}
}
// Not found yet or first to look for the remote picture, start syncing now
PicHelperState.getInstance().setSyncing(username);
Bitmap bitmap=null;
try {
// Log.i("fetchUserPic","Downloading image for "+ username +" and persisting it locally");
BufferedInputStream in = new BufferedInputStream(imageUrl.openStream());
bitmap = BitmapFactory.decodeStream(in);
if (bitmap!=null && externalStorageState.equals(Environment.MEDIA_MOUNTED)) {
File iconFile = getPictureFileForUser(username);
// Log.i("fetchUserPic","Storing picture for " + username +" at " + iconFile.getAbsolutePath());
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(iconFile));
bitmap.compress(Bitmap.CompressFormat.PNG, 0, out);
out.flush();
out.close();
}
in.close();
// if (bitmap!=null)
// bitmap.recycle();
}
catch (IOException ioe) {
Log.w("PicHelper","Failed to download the image: " + ioe.getMessage());
}
PicHelperState.getInstance().syncDone(username); // We're done, remove syncing state
// Log.i("fetchUP","loaded? bm=" + bitmap);
return bitmap;
}
return null;
}
/**
* Load the bitmap of the user icon for the given user
* @param user Screen name of the user
* @return Bitmap if present on file system or null if not found
*/
public Bitmap getBitMapForUserFromFile(User user) {
if (user==null)
return null;
String username = user.getScreenName();
return getBitMapForScreenNameFromFile(username);
}
public Bitmap getBitMapForScreenNameFromFile(String username) {
try {
if (externalStorageState.equals(Environment.MEDIA_MOUNTED)) {
File iconFile = getPictureFileForUser(username);
if (iconFile==null)
return null;
if (!iconFile.exists()) {
// Log.w("PicHelper","getPictureFileForUser("+username+"): file does not exist");
return null;
}
FileInputStream fis = new FileInputStream(iconFile);
Bitmap bi = BitmapFactory.decodeStream(fis);
fis.close();
return bi;
}
}
catch (IOException e) {
return null;
}
return null;
}
/**
* Locate the file object for the passed screen name
* @param username Screen name to lookup
* @return File object of the matching file
*/
private File getPictureFileForUser(String username) {
if (username==null)
return null;
File baseDir = Environment.getExternalStorageDirectory();
File iconDir = new File(baseDir, APP_BASE_DIR + "files/user_profiles");
if (!iconDir.exists())
iconDir.mkdirs();
File iconFile = new File(iconDir,username);
return iconFile;
}
/**
* Remove the stored user pictures
* @param olderThan Only delete pictures that are older than the passed time
*/
public void cleanup(long olderThan) {
File baseDir = Environment.getExternalStorageDirectory();
File iconDir = new File(baseDir, APP_BASE_DIR + "files/user_profiles");
File[] files = iconDir.listFiles();
if (files!=null) {
for (File file : files) {
if (file.lastModified()< olderThan) {
boolean success = file.delete();
if (!success)
Log.e("PicHelper","Could not delete " + file.getAbsolutePath());
}
}
}
}
/**
* Store the passed bitmap on the file system (recorded camera images)
*
* @param bitmap Bitmap to store
* @param file File to store in
* @param compressFormat File kind (PNG / JPEG)
* @param quality compression factor (for jpeg)
* @return Path where the file was stored or null on error
*/
public String storeBitmap(Bitmap bitmap, File file, Bitmap.CompressFormat compressFormat, int quality) {
try {
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(file));
bitmap.compress(compressFormat, quality, out);
out.flush();
out.close();
bitmap.recycle();
return file.getAbsolutePath();
} catch (IOException e) {
e.printStackTrace(); // TODO: Customise this generated block
return null;
}
}
}