/*
* Copyright (c) 2015, Nils Braden
*
* This file is part of ttrss-reader-fork. This program is free software; you
* can redistribute it and/or modify it under the terms of the GNU
* General Public License as published by the Free Software Foundation;
* either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details. You should have received a
* copy of the GNU General Public License along with this program; If
* not, see http://www.gnu.org/licenses/.
*/
package org.ttrssreader.imageCache;
import android.graphics.Bitmap;
import android.os.Environment;
import android.util.Log;
import android.widget.Toast;
import org.ttrssreader.MyApplication;
import org.ttrssreader.utils.FileUtils;
import org.ttrssreader.utils.Utils;
import java.io.File;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
/**
* Implements a cache capable of caching image files. It exposes helper methods to immediately
* access binary image data as {@link Bitmap} objects.
* Simplified it so much it now is just a Set of Strings which represent the files in the cache folder.
*/
public class ImageCache {
private static final String TAG = ImageCache.class.getSimpleName();
protected boolean isDiskCacheEnabled;
protected String diskCacheDir;
protected Set<String> cache;
public ImageCache(int initialCapacity, String cacheDir) {
this.cache = new HashSet<>(initialCapacity);
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
// Use configured output directory
File folder = new File(cacheDir);
boolean OK = folder.isDirectory() || folder.mkdirs();
if (!OK) {
// Folder could not be created, fallback to internal directory on sdcard
// Path: /sdcard/Android/data/org.ttrssreader/cache/
folder = MyApplication.context().getExternalFilesDir(Environment.DIRECTORY_PICTURES);
if (folder != null) {
OK = folder.isDirectory() || folder.mkdirs();
}
}
// Create .nomedia File in Cache-Folder so android doesn't generate thumbnails
File nomediaFile = new File(folder + File.separator + ".nomedia");
if (!nomediaFile.exists()) {
try {
if (!nomediaFile.createNewFile())
Log.w(TAG, "Couldn't create .nomedia File for Disk-Cache!");
} catch (IOException e) {
// Empty!
}
}
if (!OK) {
isDiskCacheEnabled = false;
final String msg = "Failed to create disk cache directory '" + cacheDir + "'";
Log.e(TAG, msg);
Utils.showBackgroundToast(MyApplication.context(), msg, Toast.LENGTH_LONG);
} else {
isDiskCacheEnabled = true;
diskCacheDir = folder.getAbsolutePath();
}
}
}
public boolean isDiskCacheEnabled() {
return isDiskCacheEnabled;
}
public void fillMemoryCacheFromDisk() {
File folder = new File(diskCacheDir);
File[] files = folder.listFiles();
Log.d(TAG, "Image cache before fillMemoryCacheFromDisk: " + cache.size());
if (files == null) return;
for (File file : files) {
try {
cache.add(file.getName());
} catch (RuntimeException e) {
Log.e(TAG, "Runtime Exception while doing fillMemoryCacheFromDisk: " + e.getMessage());
}
}
Log.d(TAG, "Image cache after fillMemoryCacheFromDisk: " + cache.size());
}
boolean containsKey(String key) {
return cache.contains(getFileNameForKey(key)) || isDiskCacheEnabled && getCacheFile(key).exists();
}
/**
* create uniq string from file url, which can be used as file name
*
* @param imageUrl URL of given image
* @return calculated hash
*/
public static String getHashForKey(String imageUrl) {
return imageUrl.replaceAll("[:;#~%$\"!<>|+*\\()^/,?&=]+", "+");
}
private String getFileNameForKey(String imageUrl) {
return getHashForKey(imageUrl);
}
private File getFileForKey(String key) {
return new File(diskCacheDir + "/" + getFileNameForKey(key));
}
public File getCacheFile(String key) {
File f = new File(diskCacheDir);
if (!f.exists() && !f.mkdirs()) Log.w(TAG, "Couldn't create File: " + f.getAbsolutePath());
return getFileForKey(key);
}
/**
* Only meaningful if disk caching is enabled.
*
* @return the full absolute path to the directory where files are cached, if the disk cache is
* enabled, otherwise null
*/
public String getDiskCacheDirectory() {
return diskCacheDir;
}
public boolean deleteAllCachedFiles() {
File f = new File(diskCacheDir);
return FileUtils.deleteFolderRcursive(f);
}
public synchronized void clear() {
cache.clear();
if (isDiskCacheEnabled) {
File[] cachedFiles = new File(diskCacheDir).listFiles();
if (cachedFiles == null) {
return;
}
for (File f : cachedFiles) {
if (!f.delete()) Log.e(TAG, "File couldn't be deleted: " + f.getAbsolutePath());
}
}
}
}