/*
* Copyright (C) 2008 Romain Guy
*
* 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.
*/
package org.xbmc.android.util;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import org.xbmc.api.object.ICoverArt;
import org.xbmc.api.type.MediaType;
import org.xbmc.api.type.ThumbSize;
import org.xbmc.api.type.ThumbSize.Dimension;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;
import android.os.StatFs;
public abstract class ImportUtilities {
private static final String CACHE_DIRECTORY = "xbmc";
private static final double MIN_FREE_SPACE = 3;
public static File getCacheDirectory(String type, int size) {
StringBuilder sb = new StringBuilder(CACHE_DIRECTORY);
sb.append(type);
sb.append(ThumbSize.getDir(size));
return IOUtilities.getExternalFile(sb.toString());
}
public static File getCacheFile(String type, int size, String name) {
StringBuilder sb = new StringBuilder(32);
sb.append(CACHE_DIRECTORY);
sb.append(type);
sb.append(ThumbSize.getDir(size));
sb.append("/");
sb.append(name);
return IOUtilities.getExternalFile(sb.toString());
}
public static Bitmap addCoverToCache(ICoverArt cover, Bitmap bitmap, int thumbSize) {
Bitmap sizeToReturn = null;
File cacheDirectory;
final int mediaType = cover.getMediaType();
for (int currentThumbSize : ThumbSize.values()) {
// don't save big covers
if (currentThumbSize == ThumbSize.BIG) {
if (thumbSize == currentThumbSize) {
return bitmap;
} else {
continue;
}
}
try {
cacheDirectory = ensureCache(MediaType.getArtFolder(mediaType), currentThumbSize);
} catch (IOException e) {
return null;
}
File coverFile = new File(cacheDirectory, Crc32.formatAsHexLowerCase(cover.getCrc()));
FileOutputStream out = null;
try {
final Bitmap source = bitmap;
// Centre crop and resize the image
Dimension targetDim = ThumbSize.getTargetDimension(currentThumbSize, mediaType, source.getWidth(), source.getHeight());
double targetAR = targetDim.x / targetDim.y;
double sourceAR = source.getWidth() / source.getHeight();
Bitmap cropped;
if (sourceAR > targetAR) {
int boundTop = 0;
int boundLeft = (int) ((source.getWidth() - (source.getHeight() * targetAR)) / 2);
int boundBottom = source.getHeight();
int boundRight = (int) ((source.getWidth() + (source.getHeight() * targetAR)) / 2);
cropped = Bitmap.createBitmap(source, boundLeft, boundTop, boundRight, boundBottom);
} else if (sourceAR < targetAR) {
int boundTop = (int) ((source.getHeight() - (source.getWidth() * targetAR)) / 2);
int boundLeft = 0;
int boundBottom = (int) ((source.getHeight() + (source.getWidth() * targetAR)) / 2);
int boundRight = source.getWidth();
cropped = Bitmap.createBitmap(source, boundLeft, boundTop, boundRight, boundBottom);
} else {
cropped = source;
}
Bitmap resized = Bitmap.createScaledBitmap(cropped, targetDim.x, targetDim.y, true);
resized.compress(Bitmap.CompressFormat.JPEG, 85, new FileOutputStream(coverFile));
if (thumbSize == currentThumbSize) {
sizeToReturn = resized;
}
} catch (FileNotFoundException e) {
return null;
} finally {
IOUtilities.closeStream(out);
}
}
return sizeToReturn;
}
public static int calculateSampleSize(BitmapFactory.Options options, Dimension targetDimension) {
if (targetDimension.x == 0 || targetDimension.y == 0) {
return 1;
}
Boolean scaleByHeight = Math.abs(options.outHeight - targetDimension.y) >= Math.abs(options.outWidth - targetDimension.x);
if (options.outHeight * options.outWidth * 2 >= 200 * 200 * 2) {
// Load, scaling to smallest power of 2 that'll get it <= desired dimensions
double sampleSize = scaleByHeight ? options.outHeight / targetDimension.y : options.outWidth / targetDimension.x;
return (int) Math.pow(2d, Math.floor(Math.log(sampleSize) / Math.log(2d)));
} else {
return 1;
}
}
/**
* Returns number of free bytes on the SD card.
* @return Number of free bytes on the SD card.
*/
public static long freeSpace() {
StatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath());
long blockSize = stat.getBlockSize();
long availableBlocks = stat.getAvailableBlocks();
return availableBlocks * blockSize;
}
/**
* Returns total size of SD card in bytes.
* @return Total size of SD card in bytes.
*/
public static long totalSpace() {
StatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath());
long blockSize = stat.getBlockSize();
long totalBlocks = stat.getBlockCount();
return totalBlocks * blockSize;
}
public static String assertSdCard() {
if (!android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) {
return "Your SD card is not mounted. You'll need it for caching thumbs.";
}
if (freePercentage() < MIN_FREE_SPACE) {
return "You need to have more than " + MIN_FREE_SPACE + "% of free space on your SD card.";
}
return null;
}
/**
* Returns free space in percent.
* @return Free space in percent.
*/
public static double freePercentage() {
StatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath());
long availableBlocks = stat.getAvailableBlocks();
long totalBlocks = stat.getBlockCount();
return (double)availableBlocks / (double)totalBlocks * 100;
}
private static File ensureCache(String type, int size) throws IOException {
File cacheDirectory = getCacheDirectory(type, size);
if (!cacheDirectory.exists()) {
cacheDirectory.mkdirs();
new File(cacheDirectory, ".nomedia").createNewFile();
}
return cacheDirectory;
}
public static void purgeCache() {
final int size[] = ThumbSize.values();
final int[] mediaTypes = MediaType.getTypes();
for (int i = 0; i < mediaTypes.length; i++) {
String folder = MediaType.getArtFolder(mediaTypes[i]);
for (int j = 0; j < size.length; j++) {
File cacheDirectory = getCacheDirectory(folder, size[j]);
if (cacheDirectory.exists() && cacheDirectory.isDirectory()) {
for (File file : cacheDirectory.listFiles()) {
file.delete();
}
}
}
}
}
}