/*
* Catroid: An on-device visual programming system for Android devices
* Copyright (C) 2010-2016 The Catrobat Team
* (<http://developer.catrobat.org/credits>)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* An additional term exception under section 7 of the GNU Affero
* General Public License, version 3, is available at
* http://developer.catrobat.org/license_additional_term
*
* 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.catrobat.catroid.io;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.widget.ImageView;
import org.catrobat.catroid.R;
import org.catrobat.catroid.stage.StageListener;
import org.catrobat.catroid.utils.ImageEditing;
import org.catrobat.catroid.utils.Utils;
import java.io.File;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ProjectAndSceneScreenshotLoader {
private class ScreenshotData {
public String projectName;
public String sceneName;
public boolean isBackpackScene;
public ImageView imageView;
public ScreenshotData(String projectName, String sceneName, boolean isBackpackScene, ImageView imageView) {
this.projectName = projectName;
this.sceneName = sceneName;
this.isBackpackScene = isBackpackScene;
this.imageView = imageView;
}
}
private static final int POOL_SIZE = 5;
private static final int CACHE_MAX_SIZE = 25;
private static final float LOAD_FACTOR = .75f;
private static final int INITIAL_VALUE = 13; // (N / LOAD_FACTOR) + 1
private Map<ImageView, String> imageViews = Collections.synchronizedMap(new WeakHashMap<ImageView, String>());
private ExecutorService executorService;
private Context context;
private Map<String, Bitmap> imageCache = Collections.synchronizedMap(new LinkedHashMap<String, Bitmap>(
INITIAL_VALUE, LOAD_FACTOR, true) {
private static final long serialVersionUID = 1L;
@Override
protected boolean removeEldestEntry(Map.Entry<String, Bitmap> eldest) {
return size() > CACHE_MAX_SIZE;
}
});
public ProjectAndSceneScreenshotLoader(Context context) {
executorService = Executors.newFixedThreadPool(POOL_SIZE);
this.context = context;
}
public void loadAndShowScreenshot(String projectName, String sceneName, boolean isBackpackScene, ImageView
imageView) {
String screenShotName = "";
if (projectName != null) {
screenShotName = projectName;
}
if (sceneName != null) {
screenShotName = screenShotName.concat(sceneName);
}
imageViews.put(imageView, screenShotName);
Bitmap bitmap = imageCache.get(screenShotName);
if (bitmap != null) {
imageView.setImageBitmap(bitmap);
} else {
//set a dummy or null in the meantime
imageView.setImageBitmap(null);
//queue the loading and showing process
ScreenshotData screenshotData = new ScreenshotData(projectName, sceneName, isBackpackScene, imageView);
executorService.submit(new ScreenshotLoader(screenshotData));
}
}
class ScreenshotLoader implements Runnable {
ScreenshotData projectAndSceneScreenshotData;
ScreenshotLoader(ScreenshotData screenshotData) {
this.projectAndSceneScreenshotData = screenshotData;
}
@Override
public void run() {
if (imageViewReused(projectAndSceneScreenshotData)) {
return;
}
Activity uiActivity = (Activity) projectAndSceneScreenshotData.imageView.getContext();
String pathOfScreenshot;
if (projectAndSceneScreenshotData.sceneName != null) {
if (projectAndSceneScreenshotData.isBackpackScene) {
pathOfScreenshot = Utils.buildPath(Utils.buildBackpackScenePath(projectAndSceneScreenshotData.sceneName),
StageListener.SCREENSHOT_MANUAL_FILE_NAME);
} else {
pathOfScreenshot = Utils.buildPath(Utils.buildScenePath(projectAndSceneScreenshotData
.projectName, projectAndSceneScreenshotData.sceneName),
StageListener.SCREENSHOT_MANUAL_FILE_NAME);
}
} else {
pathOfScreenshot = Utils.buildPath(Utils.buildProjectPath(projectAndSceneScreenshotData.projectName),
StageListener.SCREENSHOT_MANUAL_FILE_NAME);
}
File projectAndSceneImageFile = new File(pathOfScreenshot);
if (!(projectAndSceneImageFile.exists() && projectAndSceneImageFile.length() > 0)) {
projectAndSceneImageFile.delete();
if (projectAndSceneScreenshotData.sceneName != null) {
if (projectAndSceneScreenshotData.isBackpackScene) {
pathOfScreenshot = Utils.buildPath(Utils.buildBackpackScenePath(projectAndSceneScreenshotData.sceneName),
StageListener.SCREENSHOT_AUTOMATIC_FILE_NAME);
} else {
pathOfScreenshot = Utils.buildPath(Utils.buildScenePath(projectAndSceneScreenshotData
.projectName, projectAndSceneScreenshotData.sceneName),
StageListener.SCREENSHOT_AUTOMATIC_FILE_NAME);
}
} else {
pathOfScreenshot = Utils.buildPath(Utils.buildProjectPath(projectAndSceneScreenshotData.projectName),
StageListener.SCREENSHOT_AUTOMATIC_FILE_NAME);
}
projectAndSceneImageFile = new File(pathOfScreenshot);
}
final Bitmap projectAndSceneImage;
if (!projectAndSceneImageFile.exists() || ImageEditing.getImageDimensions(pathOfScreenshot)[0] < 0) {
projectAndSceneImage = null;
} else {
int width = context.getResources().getDimensionPixelSize(R.dimen.project_thumbnail_width);
int height = context.getResources().getDimensionPixelSize(R.dimen.project_thumbnail_height);
projectAndSceneImage = ImageEditing.getScaledBitmapFromPath(pathOfScreenshot, width, height,
ImageEditing.ResizeType.STAY_IN_RECTANGLE_WITH_SAME_ASPECT_RATIO, true);
}
String screenshotName = "";
if (projectAndSceneScreenshotData.projectName != null) {
screenshotName = projectAndSceneScreenshotData
.projectName;
}
if (projectAndSceneScreenshotData.sceneName != null) {
screenshotName = screenshotName.concat(projectAndSceneScreenshotData.sceneName);
}
imageCache.put(screenshotName, projectAndSceneImage);
if (imageViewReused(projectAndSceneScreenshotData)) {
return;
}
uiActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
if (imageViewReused(projectAndSceneScreenshotData)) {
return;
}
if (projectAndSceneImage != null) {
projectAndSceneScreenshotData.imageView.setImageBitmap(projectAndSceneImage);
} else {
projectAndSceneScreenshotData.imageView.setImageBitmap(null);
}
}
});
}
}
boolean imageViewReused(ScreenshotData projectScreenshotData) {
String tag = imageViews.get(projectScreenshotData.imageView);
String screenshotName = "";
if (projectScreenshotData.projectName != null) {
screenshotName = projectScreenshotData.projectName;
}
if (projectScreenshotData.sceneName != null) {
screenshotName = screenshotName.concat(projectScreenshotData.sceneName);
}
if (tag == null || !tag.equals(screenshotName)) {
return true;
}
return false;
}
}