mirror of
https://github.com/nextcloud/android.git
synced 2024-11-23 05:35:39 +03:00
Resized images
This commit is contained in:
parent
f838dd7b43
commit
0a649f01bb
19 changed files with 688 additions and 158 deletions
|
@ -185,6 +185,12 @@
|
|||
android:resource="@xml/exposed_filepaths" />
|
||||
</provider>
|
||||
|
||||
<provider
|
||||
android:name=".providers.DiskLruImageCacheFileProvider"
|
||||
android:authorities="org.nextcloud.imageCache.provider"
|
||||
android:exported="true">
|
||||
</provider>
|
||||
|
||||
<activity
|
||||
android:name=".authentication.AuthenticatorActivity"
|
||||
android:exported="true"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
* ownCloud Android client application
|
||||
*
|
||||
* @author Tobias Kaminsky
|
||||
|
@ -23,12 +23,14 @@ package com.owncloud.android.datamodel;
|
|||
|
||||
import android.accounts.Account;
|
||||
import android.accounts.AccountManager;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Bitmap.CompressFormat;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.media.MediaMetadataRetriever;
|
||||
|
@ -36,7 +38,9 @@ import android.media.ThumbnailUtils;
|
|||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.text.TextUtils;
|
||||
import android.view.Display;
|
||||
import android.view.MenuItem;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import com.owncloud.android.MainApp;
|
||||
|
@ -49,7 +53,9 @@ import com.owncloud.android.lib.common.operations.RemoteOperation;
|
|||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
|
||||
import com.owncloud.android.ui.adapter.DiskLruImageCache;
|
||||
import com.owncloud.android.ui.preview.PreviewImageFragment;
|
||||
import com.owncloud.android.utils.BitmapUtils;
|
||||
import com.owncloud.android.utils.ConnectivityUtils;
|
||||
import com.owncloud.android.utils.DisplayUtils.AvatarGenerationListener;
|
||||
import com.owncloud.android.utils.FileStorageUtils;
|
||||
import com.owncloud.android.utils.MimeTypeUtil;
|
||||
|
@ -58,6 +64,7 @@ import org.apache.commons.httpclient.HttpStatus;
|
|||
import org.apache.commons.httpclient.methods.GetMethod;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
|
@ -69,6 +76,9 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
|||
*/
|
||||
public class ThumbnailsCacheManager {
|
||||
|
||||
public static final String PREFIX_RESIZED_IMAGE = "r";
|
||||
public static final String PREFIX_THUMBNAIL = "t";
|
||||
|
||||
private static final String TAG = ThumbnailsCacheManager.class.getSimpleName();
|
||||
|
||||
private static final String CACHE_FOLDER = "thumbnailCache";
|
||||
|
@ -77,7 +87,7 @@ public class ThumbnailsCacheManager {
|
|||
private static DiskLruImageCache mThumbnailCache = null;
|
||||
private static boolean mThumbnailCacheStarting = true;
|
||||
|
||||
private static final int DISK_CACHE_SIZE = 1024 * 1024 * 10; // 10MB
|
||||
private static final int DISK_CACHE_SIZE = 1024 * 1024 * 200; // 200MB
|
||||
private static final CompressFormat mCompressFormat = CompressFormat.JPEG;
|
||||
private static final int mCompressQuality = 70;
|
||||
private static OwnCloudClient mClient = null;
|
||||
|
@ -106,19 +116,19 @@ public class ThumbnailsCacheManager {
|
|||
try {
|
||||
// Check if media is mounted or storage is built-in, if so,
|
||||
// try and use external cache dir; otherwise use internal cache dir
|
||||
final String cachePath =
|
||||
MainApp.getAppContext().getExternalCacheDir().getPath() +
|
||||
File.separator + CACHE_FOLDER;
|
||||
File cacheDir = MainApp.getAppContext().getExternalCacheDir();
|
||||
|
||||
if (cacheDir != null) {
|
||||
String cachePath = cacheDir.getPath() + File.separator + CACHE_FOLDER;
|
||||
Log_OC.d(TAG, "create dir: " + cachePath);
|
||||
final File diskCacheDir = new File(cachePath);
|
||||
mThumbnailCache = new DiskLruImageCache(
|
||||
diskCacheDir,
|
||||
DISK_CACHE_SIZE,
|
||||
mCompressFormat,
|
||||
mCompressQuality
|
||||
);
|
||||
} catch (Exception e) {
|
||||
Log_OC.d(TAG, "Thumbnail cache could not be opened ", e);
|
||||
File diskCacheDir = new File(cachePath);
|
||||
mThumbnailCache = new DiskLruImageCache(diskCacheDir, DISK_CACHE_SIZE, mCompressFormat,
|
||||
mCompressQuality);
|
||||
} else {
|
||||
throw new FileNotFoundException("Thumbnail cache could not be opened");
|
||||
}
|
||||
} catch (java.io.IOException e) {
|
||||
Log_OC.d(TAG, e.getMessage());
|
||||
mThumbnailCache = null;
|
||||
}
|
||||
}
|
||||
|
@ -139,17 +149,32 @@ public class ThumbnailsCacheManager {
|
|||
return Math.round(r.getDimension(R.dimen.file_icon_size_grid));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts dimension of screen as point
|
||||
*
|
||||
* @return Point
|
||||
*/
|
||||
private static Point getScreenDimension() {
|
||||
WindowManager wm = (WindowManager) MainApp.getAppContext().
|
||||
getSystemService(Context.WINDOW_SERVICE);
|
||||
Display display = wm.getDefaultDisplay();
|
||||
Point point = new Point();
|
||||
display.getSize(point);
|
||||
return point;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add thumbnail to cache
|
||||
* @param imageKey: thumb key
|
||||
* @param bitmap: image for extracting thumbnail
|
||||
* @param path: image path
|
||||
* @param px: thumbnail dp
|
||||
* @param pxW: thumbnail width in pixel
|
||||
* @param pxH: thumbnail height in pixel
|
||||
* @return Bitmap
|
||||
*/
|
||||
private static Bitmap addThumbnailToCache(String imageKey, Bitmap bitmap, String path, int px){
|
||||
private static Bitmap addThumbnailToCache(String imageKey, Bitmap bitmap, String path, int pxW, int pxH){
|
||||
|
||||
Bitmap thumbnail = ThumbnailUtils.extractThumbnail(bitmap, px, px);
|
||||
Bitmap thumbnail = ThumbnailUtils.extractThumbnail(bitmap, pxW, pxH);
|
||||
|
||||
// Rotate image, obeying exif tag
|
||||
thumbnail = BitmapUtils.rotateImage(thumbnail,path);
|
||||
|
@ -185,7 +210,180 @@ public class ThumbnailsCacheManager {
|
|||
return null;
|
||||
}
|
||||
|
||||
public static class ThumbnailGenerationTask extends AsyncTask<Object, Void, Bitmap> {
|
||||
public static class ResizedImageGenerationTask extends AsyncTask<Object, Void, Bitmap> {
|
||||
private PreviewImageFragment previewImageFragment;
|
||||
private FileDataStorageManager storageManager;
|
||||
private Account account;
|
||||
private WeakReference<ImageView> imageViewReference;
|
||||
private OCFile file;
|
||||
|
||||
|
||||
public ResizedImageGenerationTask(PreviewImageFragment previewImageFragment, ImageView imageView,
|
||||
FileDataStorageManager storageManager, Account account)
|
||||
throws IllegalArgumentException {
|
||||
this.previewImageFragment = previewImageFragment;
|
||||
imageViewReference = new WeakReference<>(imageView);
|
||||
this.storageManager = storageManager;
|
||||
this.account = account;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Bitmap doInBackground(Object... params) {
|
||||
Bitmap thumbnail = null;
|
||||
|
||||
file = (OCFile) params[0];
|
||||
|
||||
try {
|
||||
if (account != null) {
|
||||
OwnCloudAccount ocAccount = new OwnCloudAccount(account, MainApp.getAppContext());
|
||||
mClient = OwnCloudClientManagerFactory.getDefaultSingleton().getClientFor(ocAccount,
|
||||
MainApp.getAppContext());
|
||||
}
|
||||
|
||||
thumbnail = doResizedImageInBackground();
|
||||
|
||||
if (MimeTypeUtil.isVideo(file) && thumbnail != null) {
|
||||
thumbnail = addVideoOverlay(thumbnail);
|
||||
}
|
||||
|
||||
} catch (OutOfMemoryError oome) {
|
||||
System.gc();
|
||||
} catch (Throwable t) {
|
||||
// the app should never break due to a problem with thumbnails
|
||||
Log_OC.e(TAG, "Generation of thumbnail for " + file + " failed", t);
|
||||
}
|
||||
|
||||
return thumbnail;
|
||||
}
|
||||
|
||||
private Bitmap doResizedImageInBackground() {
|
||||
Bitmap thumbnail;
|
||||
|
||||
String imageKey = PREFIX_RESIZED_IMAGE + String.valueOf(file.getRemoteId());
|
||||
|
||||
// Check disk cache in background thread
|
||||
thumbnail = getBitmapFromDiskCache(imageKey);
|
||||
|
||||
// Not found in disk cache
|
||||
if (thumbnail == null || file.needsUpdateThumbnail()) {
|
||||
Point p = getScreenDimension();
|
||||
int pxW = p.x;
|
||||
int pxH = p.y;
|
||||
|
||||
if (file.isDown()) {
|
||||
Bitmap bitmap = BitmapUtils.decodeSampledBitmapFromFile(
|
||||
file.getStoragePath(), pxW, pxH);
|
||||
|
||||
if (bitmap != null) {
|
||||
// Handle PNG
|
||||
if (file.getMimetype().equalsIgnoreCase("image/png")) {
|
||||
bitmap = handlePNG(bitmap, pxW);
|
||||
}
|
||||
|
||||
thumbnail = addThumbnailToCache(imageKey, bitmap, file.getStoragePath(), pxW, pxH);
|
||||
|
||||
file.setNeedsUpdateThumbnail(false);
|
||||
storageManager.saveFile(file);
|
||||
}
|
||||
|
||||
} else {
|
||||
// Download thumbnail from server
|
||||
OwnCloudVersion serverOCVersion = AccountUtils.getServerVersion(account);
|
||||
if (mClient != null && serverOCVersion != null) {
|
||||
if (serverOCVersion.supportsRemoteThumbnails()) {
|
||||
GetMethod getMethod = null;
|
||||
try {
|
||||
// resized image via gallery app
|
||||
String uri = mClient.getBaseUri() + "" +
|
||||
"/index.php/apps/gallery/api/preview/" +
|
||||
Integer.parseInt(file.getRemoteId().substring(0, 8)) +
|
||||
"/" + pxW + "/" + pxH;
|
||||
Log_OC.d(TAG, "generate resizedImage: " + file.getFileName() +
|
||||
" URI: " + uri);
|
||||
getMethod = new GetMethod(uri);
|
||||
getMethod.setRequestHeader("Cookie",
|
||||
"nc_sameSiteCookielax=true;nc_sameSiteCookiestrict=true");
|
||||
int status = mClient.executeMethod(getMethod);
|
||||
if (status == HttpStatus.SC_OK) {
|
||||
InputStream inputStream = getMethod.getResponseBodyAsStream();
|
||||
thumbnail = BitmapFactory.decodeStream(inputStream);
|
||||
} else {
|
||||
mClient.exhaustResponse(getMethod.getResponseBodyAsStream());
|
||||
}
|
||||
|
||||
// Handle PNG
|
||||
if (file.getMimetype().equalsIgnoreCase("image/png")) {
|
||||
thumbnail = handlePNG(thumbnail, pxW);
|
||||
}
|
||||
|
||||
// Add thumbnail to cache
|
||||
if (thumbnail != null) {
|
||||
Log_OC.d(TAG, "add thumbnail to cache: " + file.getFileName());
|
||||
addBitmapToCache(imageKey, thumbnail);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
Log_OC.d(TAG, e.getMessage(), e);
|
||||
} finally {
|
||||
if (getMethod != null) {
|
||||
getMethod.releaseConnection();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Log_OC.d(TAG, "Server too old");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return thumbnail;
|
||||
|
||||
}
|
||||
|
||||
protected void onPostExecute(Bitmap bitmap) {
|
||||
if (imageViewReference != null) {
|
||||
final ImageView imageView = imageViewReference.get();
|
||||
|
||||
if (bitmap != null) {
|
||||
final ResizedImageGenerationTask bitmapWorkerTask = getResizedImageGenerationWorkerTask(imageView);
|
||||
|
||||
if (this == bitmapWorkerTask) {
|
||||
String tagId = String.valueOf(file.getFileId());
|
||||
|
||||
if (String.valueOf(imageView.getTag()).equals(tagId)) {
|
||||
imageView.setImageBitmap(bitmap);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (ConnectivityUtils.isAppConnected(MainApp.getAppContext())) {
|
||||
previewImageFragment.setErrorPreviewMessage();
|
||||
} else {
|
||||
previewImageFragment.setNoConnectionErrorMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class ThumbnailGenerationTaskObject {
|
||||
private Object file;
|
||||
private String imageKey;
|
||||
|
||||
public ThumbnailGenerationTaskObject(Object file, String imageKey) {
|
||||
this.file = file;
|
||||
this.imageKey = imageKey;
|
||||
}
|
||||
|
||||
private Object getFile() {
|
||||
return file;
|
||||
}
|
||||
|
||||
private String getImageKey() {
|
||||
return imageKey;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ThumbnailGenerationTask extends AsyncTask<ThumbnailGenerationTaskObject, Void, Bitmap> {
|
||||
private final WeakReference<ImageView> mImageViewReference;
|
||||
private static Account mAccount;
|
||||
private ArrayList<ThumbnailGenerationTask> mAsyncTasks = null;
|
||||
|
@ -232,7 +430,7 @@ public class ThumbnailsCacheManager {
|
|||
|
||||
@SuppressFBWarnings("Dm")
|
||||
@Override
|
||||
protected Bitmap doInBackground(Object... params) {
|
||||
protected Bitmap doInBackground(ThumbnailGenerationTaskObject... params) {
|
||||
Bitmap thumbnail = null;
|
||||
|
||||
try {
|
||||
|
@ -245,13 +443,12 @@ public class ThumbnailsCacheManager {
|
|||
getClientFor(ocAccount, MainApp.getAppContext());
|
||||
}
|
||||
|
||||
mFile = params[0];
|
||||
if (params.length == 2) {
|
||||
mImageKey = (String) params[1];
|
||||
}
|
||||
ThumbnailGenerationTaskObject object = params[0];
|
||||
mFile = object.getFile();
|
||||
mImageKey = object.getImageKey();
|
||||
|
||||
if (mFile instanceof OCFile) {
|
||||
thumbnail = doOCFileInBackground();
|
||||
thumbnail = doThumbnailFromOCFileInBackground();
|
||||
|
||||
if (MimeTypeUtil.isVideo((OCFile) mFile) && thumbnail != null) {
|
||||
thumbnail = addVideoOverlay(thumbnail);
|
||||
|
@ -300,42 +497,31 @@ public class ThumbnailsCacheManager {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts size of file icon from dp to pixel
|
||||
* @return int
|
||||
*/
|
||||
private int getThumbnailDimension(){
|
||||
// Converts dp to pixel
|
||||
Resources r = MainApp.getAppContext().getResources();
|
||||
Double d = Math.pow(2,Math.floor(Math.log(r.getDimension(R.dimen.file_icon_size_grid))/Math.log(2)));
|
||||
return d.intValue();
|
||||
}
|
||||
|
||||
private Bitmap doOCFileInBackground() {
|
||||
OCFile file = (OCFile)mFile;
|
||||
|
||||
final String imageKey = String.valueOf(file.getRemoteId());
|
||||
private Bitmap doThumbnailFromOCFileInBackground() {
|
||||
Bitmap thumbnail;
|
||||
OCFile file = (OCFile) mFile;
|
||||
String imageKey = PREFIX_THUMBNAIL + String.valueOf(file.getRemoteId());
|
||||
|
||||
// Check disk cache in background thread
|
||||
Bitmap thumbnail = getBitmapFromDiskCache(imageKey);
|
||||
thumbnail = getBitmapFromDiskCache(imageKey);
|
||||
|
||||
// Not found in disk cache
|
||||
if (thumbnail == null || file.needsUpdateThumbnail()) {
|
||||
|
||||
int px = getThumbnailDimension();
|
||||
int pxW;
|
||||
int pxH;
|
||||
pxW = pxH = getThumbnailDimension();
|
||||
|
||||
if (file.isDown()) {
|
||||
Bitmap temp = BitmapUtils.decodeSampledBitmapFromFile(
|
||||
file.getStoragePath(), px, px);
|
||||
Bitmap bitmap = ThumbnailUtils.extractThumbnail(temp, px, px);
|
||||
Bitmap bitmap = BitmapUtils.decodeSampledBitmapFromFile(
|
||||
file.getStoragePath(), pxW, pxH);
|
||||
|
||||
if (bitmap != null) {
|
||||
// Handle PNG
|
||||
if (file.getMimetype().equalsIgnoreCase("image/png")) {
|
||||
bitmap = handlePNG(bitmap, px);
|
||||
bitmap = handlePNG(bitmap, pxW);
|
||||
}
|
||||
|
||||
thumbnail = addThumbnailToCache(imageKey, bitmap, file.getStoragePath(), px);
|
||||
thumbnail = addThumbnailToCache(imageKey, bitmap, file.getStoragePath(), pxW, pxH);
|
||||
|
||||
file.setNeedsUpdateThumbnail(false);
|
||||
mStorageManager.saveFile(file);
|
||||
|
@ -348,10 +534,12 @@ public class ThumbnailsCacheManager {
|
|||
if (serverOCVersion.supportsRemoteThumbnails()) {
|
||||
getMethod = null;
|
||||
try {
|
||||
// thumbnail
|
||||
String uri = mClient.getBaseUri() + "" +
|
||||
"/index.php/apps/files/api/v1/thumbnail/" +
|
||||
px + "/" + px + Uri.encode(file.getRemotePath(), "/");
|
||||
Log_OC.d("Thumbnail", "URI: " + uri);
|
||||
pxW + "/" + pxH + Uri.encode(file.getRemotePath(), "/");
|
||||
Log_OC.d(TAG, "generate thumbnail: " + file.getFileName() +
|
||||
" URI: " + uri);
|
||||
getMethod = new GetMethod(uri);
|
||||
getMethod.setRequestHeader("Cookie",
|
||||
"nc_sameSiteCookielax=true;nc_sameSiteCookiestrict=true");
|
||||
|
@ -363,20 +551,22 @@ public class ThumbnailsCacheManager {
|
|||
if (status == HttpStatus.SC_OK) {
|
||||
InputStream inputStream = getMethod.getResponseBodyAsStream();
|
||||
Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
|
||||
thumbnail = ThumbnailUtils.extractThumbnail(bitmap, px, px);
|
||||
thumbnail = ThumbnailUtils.extractThumbnail(bitmap, pxW, pxH);
|
||||
} else {
|
||||
mClient.exhaustResponse(getMethod.getResponseBodyAsStream());
|
||||
}
|
||||
|
||||
// Handle PNG
|
||||
if (file.getMimetype().equalsIgnoreCase("image/png")) {
|
||||
thumbnail = handlePNG(thumbnail, px);
|
||||
thumbnail = handlePNG(thumbnail, pxW);
|
||||
}
|
||||
|
||||
// Add thumbnail to cache
|
||||
if (thumbnail != null) {
|
||||
Log_OC.d(TAG, "add thumbnail to cache: " + file.getFileName());
|
||||
addBitmapToCache(imageKey, thumbnail);
|
||||
}
|
||||
} else {
|
||||
mClient.exhaustResponse(getMethod.getResponseBodyAsStream());
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
Log_OC.d(TAG, e.getMessage(), e);
|
||||
} finally {
|
||||
|
@ -395,6 +585,18 @@ public class ThumbnailsCacheManager {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts size of file icon from dp to pixel
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private int getThumbnailDimension() {
|
||||
// Converts dp to pixel
|
||||
Resources r = MainApp.getAppContext().getResources();
|
||||
Double d = Math.pow(2, Math.floor(Math.log(r.getDimension(R.dimen.file_icon_size_grid)) / Math.log(2)));
|
||||
return d.intValue();
|
||||
}
|
||||
|
||||
private Bitmap doFileInBackground() {
|
||||
File file = (File)mFile;
|
||||
|
||||
|
@ -405,19 +607,22 @@ public class ThumbnailsCacheManager {
|
|||
imageKey = String.valueOf(file.hashCode());
|
||||
}
|
||||
|
||||
// local file should always generate a thumbnail
|
||||
mImageKey = PREFIX_THUMBNAIL + mImageKey;
|
||||
|
||||
// Check disk cache in background thread
|
||||
Bitmap thumbnail = getBitmapFromDiskCache(imageKey);
|
||||
|
||||
// Not found in disk cache
|
||||
if (thumbnail == null) {
|
||||
int pxW;
|
||||
int pxH;
|
||||
pxW = pxH = getThumbnailDimension();
|
||||
|
||||
int px = getThumbnailDimension();
|
||||
|
||||
Bitmap bitmap = BitmapUtils.decodeSampledBitmapFromFile(
|
||||
file.getAbsolutePath(), px, px);
|
||||
Bitmap bitmap = BitmapUtils.decodeSampledBitmapFromFile(file.getAbsolutePath(), pxW, pxH);
|
||||
|
||||
if (bitmap != null) {
|
||||
thumbnail = addThumbnailToCache(imageKey, bitmap, file.getPath(), px);
|
||||
thumbnail = addThumbnailToCache(imageKey, bitmap, file.getPath(), pxW, pxH);
|
||||
}
|
||||
}
|
||||
return thumbnail;
|
||||
|
@ -514,7 +719,7 @@ public class ThumbnailsCacheManager {
|
|||
Bitmap bitmap = BitmapUtils.decodeSampledBitmapFromFile(file.getAbsolutePath(), px, px);
|
||||
|
||||
if (bitmap != null) {
|
||||
thumbnail = addThumbnailToCache(imageKey, bitmap, file.getPath(), px);
|
||||
thumbnail = addThumbnailToCache(imageKey, bitmap, file.getPath(), px, px);
|
||||
}
|
||||
} else if (Type.VIDEO.equals(type)) {
|
||||
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
|
||||
|
@ -541,7 +746,7 @@ public class ThumbnailsCacheManager {
|
|||
int max = Math.max(width, height);
|
||||
if (max > px) {
|
||||
thumbnail = BitmapUtils.scaleBitmap(thumbnail, px, width, height, max);
|
||||
thumbnail = addThumbnailToCache(imageKey, thumbnail, file.getPath(), px);
|
||||
thumbnail = addThumbnailToCache(imageKey, thumbnail, file.getPath(), px, px);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -605,27 +810,6 @@ public class ThumbnailsCacheManager {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add thumbnail to cache
|
||||
* @param imageKey: thumb key
|
||||
* @param bitmap: image for extracting thumbnail
|
||||
* @param path: image path
|
||||
* @param px: thumbnail dp
|
||||
* @return Bitmap
|
||||
*/
|
||||
private Bitmap addThumbnailToCache(String imageKey, Bitmap bitmap, String path, int px){
|
||||
|
||||
Bitmap thumbnail = ThumbnailUtils.extractThumbnail(bitmap, px, px);
|
||||
|
||||
// Rotate image, obeying exif tag
|
||||
thumbnail = BitmapUtils.rotateImage(thumbnail,path);
|
||||
|
||||
// Add thumbnail to cache
|
||||
addBitmapToCache(imageKey, thumbnail);
|
||||
|
||||
return thumbnail;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts size of file icon from dp to pixel
|
||||
* @return int
|
||||
|
@ -774,6 +958,17 @@ public class ThumbnailsCacheManager {
|
|||
return null;
|
||||
}
|
||||
|
||||
private static ResizedImageGenerationTask getResizedImageGenerationWorkerTask(ImageView imageView) {
|
||||
if (imageView != null) {
|
||||
final Drawable drawable = imageView.getDrawable();
|
||||
if (drawable instanceof AsyncResizedImageDrawable) {
|
||||
final AsyncResizedImageDrawable asyncDrawable = (AsyncResizedImageDrawable) drawable;
|
||||
return asyncDrawable.getBitmapWorkerTask();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Bitmap addVideoOverlay(Bitmap thumbnail){
|
||||
Bitmap playButton = BitmapFactory.decodeResource(MainApp.getAppContext().getResources(),
|
||||
R.drawable.view_play);
|
||||
|
@ -852,22 +1047,30 @@ public class ThumbnailsCacheManager {
|
|||
}
|
||||
}
|
||||
|
||||
public static class AsyncMediaThumbnailDrawable extends BitmapDrawable {
|
||||
private final WeakReference<MediaThumbnailGenerationTask> bitmapWorkerTaskReference;
|
||||
|
||||
public AsyncMediaThumbnailDrawable(
|
||||
Resources res, Bitmap bitmap, MediaThumbnailGenerationTask bitmapWorkerTask
|
||||
) {
|
||||
public static class AsyncResizedImageDrawable extends BitmapDrawable {
|
||||
private final WeakReference<ResizedImageGenerationTask> bitmapWorkerTaskReference;
|
||||
|
||||
public AsyncResizedImageDrawable(Resources res, Bitmap bitmap, ResizedImageGenerationTask bitmapWorkerTask) {
|
||||
super(res, bitmap);
|
||||
bitmapWorkerTaskReference = new WeakReference<>(bitmapWorkerTask);
|
||||
}
|
||||
|
||||
public MediaThumbnailGenerationTask getBitmapWorkerTask() {
|
||||
private ResizedImageGenerationTask getBitmapWorkerTask() {
|
||||
return bitmapWorkerTaskReference.get();
|
||||
}
|
||||
}
|
||||
|
||||
public static class AsyncMediaThumbnailDrawable extends BitmapDrawable {
|
||||
private final WeakReference<MediaThumbnailGenerationTask> bitmapWorkerTaskReference;
|
||||
|
||||
public AsyncMediaThumbnailDrawable(Resources res, Bitmap bitmap,
|
||||
MediaThumbnailGenerationTask bitmapWorkerTask) {
|
||||
|
||||
super(res, bitmap);
|
||||
bitmapWorkerTaskReference = new WeakReference<>(bitmapWorkerTask);
|
||||
}
|
||||
}
|
||||
|
||||
public static class AsyncAvatarDrawable extends BitmapDrawable {
|
||||
private final WeakReference<AvatarGenerationTask> avatarWorkerTaskReference;
|
||||
|
||||
|
@ -897,4 +1100,22 @@ public class ThumbnailsCacheManager {
|
|||
|
||||
return resultBitmap;
|
||||
}
|
||||
|
||||
public static void generateResizedImage(OCFile file) {
|
||||
Point p = getScreenDimension();
|
||||
int pxW = p.x;
|
||||
int pxH = p.y;
|
||||
String imageKey = PREFIX_RESIZED_IMAGE + String.valueOf(file.getRemoteId());
|
||||
|
||||
Bitmap bitmap = BitmapUtils.decodeSampledBitmapFromFile(file.getStoragePath(), pxW, pxH);
|
||||
|
||||
if (bitmap != null) {
|
||||
// Handle PNG
|
||||
if (file.getMimetype().equalsIgnoreCase("image/png")) {
|
||||
bitmap = handlePNG(bitmap, pxW);
|
||||
}
|
||||
|
||||
addThumbnailToCache(imageKey, bitmap, file.getStoragePath(), pxW, pxH);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1071,11 +1071,10 @@ public class FileUploader extends Service
|
|||
final ThumbnailsCacheManager.ThumbnailGenerationTask task =
|
||||
new ThumbnailsCacheManager.ThumbnailGenerationTask(mStorageManager, mCurrentAccount);
|
||||
|
||||
Object[] params = new Object[2];
|
||||
params[0] = new File(mCurrentUpload.getOriginalStoragePath());
|
||||
params[1] = mCurrentUpload.getFile().getRemoteId();
|
||||
File file = new File(mCurrentUpload.getOriginalStoragePath());
|
||||
String remoteId = mCurrentUpload.getFile().getRemoteId();
|
||||
|
||||
task.execute(params);
|
||||
task.execute(new ThumbnailsCacheManager.ThumbnailGenerationTaskObject(file, remoteId));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
package com.owncloud.android.operations;
|
||||
|
||||
import com.owncloud.android.datamodel.OCFile;
|
||||
import com.owncloud.android.datamodel.ThumbnailsCacheManager;
|
||||
import com.owncloud.android.lib.common.OwnCloudClient;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
|
||||
|
@ -75,6 +76,9 @@ public class RemoveFileOperation extends SyncOperation {
|
|||
|
||||
mFileToRemove = getStorageManager().getFileByPath(mRemotePath);
|
||||
|
||||
// store resized image
|
||||
ThumbnailsCacheManager.generateResizedImage(mFileToRemove);
|
||||
|
||||
boolean localRemovalFailed = false;
|
||||
if (!mOnlyLocalCopy) {
|
||||
RemoveRemoteFileOperation operation = new RemoveRemoteFileOperation(mRemotePath);
|
||||
|
|
|
@ -918,7 +918,7 @@ public class UploadFileOperation extends SyncOperation {
|
|||
// generate new Thumbnail
|
||||
final ThumbnailsCacheManager.ThumbnailGenerationTask task =
|
||||
new ThumbnailsCacheManager.ThumbnailGenerationTask(getStorageManager(), mAccount);
|
||||
task.execute(file);
|
||||
task.execute(new ThumbnailsCacheManager.ThumbnailGenerationTaskObject(file, file.getRemoteId()));
|
||||
}
|
||||
|
||||
private void updateOCFile(OCFile file, RemoteFile remoteFile) {
|
||||
|
|
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
* ownCloud Android client application
|
||||
*
|
||||
* Copyright (C) 2016 Tobias Kaminsky
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or 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 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 com.owncloud.android.providers;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.content.ContentProvider;
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
import android.database.MatrixCursor;
|
||||
import android.graphics.Bitmap;
|
||||
import android.net.Uri;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.provider.OpenableColumns;
|
||||
|
||||
import com.owncloud.android.MainApp;
|
||||
import com.owncloud.android.authentication.AccountUtils;
|
||||
import com.owncloud.android.datamodel.FileDataStorageManager;
|
||||
import com.owncloud.android.datamodel.OCFile;
|
||||
import com.owncloud.android.datamodel.ThumbnailsCacheManager;
|
||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
|
||||
public class DiskLruImageCacheFileProvider extends ContentProvider {
|
||||
public static final String AUTHORITY = "org.nextcloud.imageCache.provider";
|
||||
public static final String TAG = DiskLruImageCacheFileProvider.class.getSimpleName();
|
||||
|
||||
@Override
|
||||
public boolean onCreate() {
|
||||
return true;
|
||||
}
|
||||
|
||||
private OCFile getFile(Uri uri) {
|
||||
Account account = AccountUtils.getCurrentOwnCloudAccount(MainApp.getAppContext());
|
||||
FileDataStorageManager fileDataStorageManager = new FileDataStorageManager(account,
|
||||
MainApp.getAppContext().getContentResolver());
|
||||
|
||||
return fileDataStorageManager.getFileByPath(uri.getPath());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
|
||||
OCFile ocFile = getFile(uri);
|
||||
|
||||
Bitmap thumbnail = ThumbnailsCacheManager.getBitmapFromDiskCache(
|
||||
String.valueOf(ThumbnailsCacheManager.PREFIX_RESIZED_IMAGE + ocFile.getRemoteId()));
|
||||
|
||||
// fallback to thumbnail
|
||||
if (thumbnail == null) {
|
||||
thumbnail = ThumbnailsCacheManager.getBitmapFromDiskCache(
|
||||
String.valueOf(ThumbnailsCacheManager.PREFIX_THUMBNAIL + ocFile.getRemoteId()));
|
||||
}
|
||||
|
||||
// fallback to default image
|
||||
if (thumbnail == null) {
|
||||
thumbnail = ThumbnailsCacheManager.mDefaultImg;
|
||||
}
|
||||
|
||||
// create a file to write bitmap data
|
||||
File f = new File(MainApp.getAppContext().getCacheDir(), ocFile.getFileName());
|
||||
try {
|
||||
f.createNewFile();
|
||||
|
||||
//Convert bitmap to byte array
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
thumbnail.compress(Bitmap.CompressFormat.JPEG, 90, bos);
|
||||
byte[] bitmapData = bos.toByteArray();
|
||||
|
||||
//write the bytes in file
|
||||
FileOutputStream fos = null;
|
||||
try {
|
||||
fos = new FileOutputStream(f);
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
fos.write(bitmapData);
|
||||
fos.flush();
|
||||
fos.close();
|
||||
|
||||
} catch (Exception e) {
|
||||
Log_OC.e(TAG, "Error opening file: " + e.getMessage());
|
||||
}
|
||||
|
||||
return ParcelFileDescriptor.open(f, ParcelFileDescriptor.MODE_READ_ONLY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType(Uri uri) {
|
||||
OCFile ocFile = getFile(uri);
|
||||
return ocFile.getMimetype();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cursor query(Uri uri, String[] arg1, String arg2, String[] arg3, String arg4) {
|
||||
MatrixCursor cursor = null;
|
||||
|
||||
OCFile ocFile = getFile(uri);
|
||||
File file = new File(MainApp.getAppContext().getCacheDir(), ocFile.getFileName());
|
||||
if (file.exists()) {
|
||||
cursor = new MatrixCursor(new String[] {
|
||||
OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE });
|
||||
cursor.addRow(new Object[] { uri.getLastPathSegment(),
|
||||
file.length() });
|
||||
}
|
||||
|
||||
return cursor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Uri insert(Uri uri, ContentValues values) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int delete(Uri uri, String selection, String[] selectionArgs) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
|
||||
return 0;
|
||||
}
|
||||
}
|
|
@ -449,7 +449,8 @@ public class ExpandableUploadListAdapter extends BaseExpandableListAdapter imple
|
|||
task
|
||||
);
|
||||
fileIcon.setImageDrawable(asyncDrawable);
|
||||
task.execute(fakeFileToCheatThumbnailsCacheManagerInterface);
|
||||
task.execute(new ThumbnailsCacheManager.ThumbnailGenerationTaskObject(
|
||||
fakeFileToCheatThumbnailsCacheManagerInterface, null));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -485,7 +486,7 @@ public class ExpandableUploadListAdapter extends BaseExpandableListAdapter imple
|
|||
task
|
||||
);
|
||||
fileIcon.setImageDrawable(asyncDrawable);
|
||||
task.execute(file);
|
||||
task.execute(new ThumbnailsCacheManager.ThumbnailGenerationTaskObject(file, null));
|
||||
Log_OC.v(TAG, "Executing task to generate a new thumbnail");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -343,7 +343,9 @@ public class FileListListAdapter extends BaseAdapter {
|
|||
if (!file.isFolder()) {
|
||||
if ((MimeTypeUtil.isImage(file) || MimeTypeUtil.isVideo(file)) && file.getRemoteId() != null) {
|
||||
// Thumbnail in Cache?
|
||||
Bitmap thumbnail = ThumbnailsCacheManager.getBitmapFromDiskCache(file.getRemoteId());
|
||||
Bitmap thumbnail = ThumbnailsCacheManager.getBitmapFromDiskCache(
|
||||
ThumbnailsCacheManager.PREFIX_THUMBNAIL + String.valueOf(file.getRemoteId())
|
||||
);
|
||||
if (thumbnail != null && !file.needsUpdateThumbnail()) {
|
||||
|
||||
if (MimeTypeUtil.isVideo(file)) {
|
||||
|
@ -375,7 +377,8 @@ public class FileListListAdapter extends BaseAdapter {
|
|||
);
|
||||
fileIcon.setImageDrawable(asyncDrawable);
|
||||
asyncTasks.add(task);
|
||||
task.execute(file);
|
||||
task.execute(new ThumbnailsCacheManager.ThumbnailGenerationTaskObject(file,
|
||||
file.getRemoteId()));
|
||||
} catch (IllegalArgumentException e) {
|
||||
Log_OC.d(TAG, "ThumbnailGenerationTask : " + e.getMessage());
|
||||
}
|
||||
|
|
|
@ -204,7 +204,7 @@ public class LocalFileListAdapter extends BaseAdapter implements FilterableListA
|
|||
if (MimeTypeUtil.isImage(file)){
|
||||
// Thumbnail in Cache?
|
||||
Bitmap thumbnail = ThumbnailsCacheManager.getBitmapFromDiskCache(
|
||||
String.valueOf(file.hashCode())
|
||||
ThumbnailsCacheManager.PREFIX_THUMBNAIL + String.valueOf(file.hashCode())
|
||||
);
|
||||
if (thumbnail != null){
|
||||
fileIcon.setImageBitmap(thumbnail);
|
||||
|
@ -226,7 +226,7 @@ public class LocalFileListAdapter extends BaseAdapter implements FilterableListA
|
|||
task
|
||||
);
|
||||
fileIcon.setImageDrawable(asyncDrawable);
|
||||
task.execute(file);
|
||||
task.execute(new ThumbnailsCacheManager.ThumbnailGenerationTaskObject(file, null));
|
||||
Log_OC.v(TAG, "Executing task to generate a new thumbnail");
|
||||
|
||||
} // else, already being generated, don't restart it
|
||||
|
|
|
@ -122,7 +122,7 @@ public class UploaderAdapter extends SimpleAdapter {
|
|||
task
|
||||
);
|
||||
fileIcon.setImageDrawable(asyncDrawable);
|
||||
task.execute(file);
|
||||
task.execute(new ThumbnailsCacheManager.ThumbnailGenerationTaskObject(file, file.getRemoteId()));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -339,14 +339,10 @@ public class FileDetailFragment extends FileFragment implements OnClickListener,
|
|||
return true;
|
||||
}
|
||||
case R.id.action_send_file: {
|
||||
// Obtain the file
|
||||
if (!getFile().isDown()) { // Download the file
|
||||
Log_OC.d(TAG, getFile().getRemotePath() + " : File must be downloaded");
|
||||
((FileDisplayActivity) mContainerActivity).startDownloadForSending(getFile(),
|
||||
OCFileListFragment.DOWNLOAD_SEND);
|
||||
}
|
||||
else {
|
||||
if (getFile().isDown()) {
|
||||
mContainerActivity.getFileOperationsHelper().sendDownloadedFile(getFile());
|
||||
} else {
|
||||
mContainerActivity.getFileOperationsHelper().sendCachedImage(getFile());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -508,7 +504,7 @@ public class FileDetailFragment extends FileFragment implements OnClickListener,
|
|||
task
|
||||
);
|
||||
iv.setImageDrawable(asyncDrawable);
|
||||
task.execute(file);
|
||||
task.execute(new ThumbnailsCacheManager.ThumbnailGenerationTaskObject(file, file.getRemoteId()));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -970,15 +970,22 @@ public class OCFileListFragment extends ExtendedListFragment implements OCFileLi
|
|||
return true;
|
||||
}
|
||||
case R.id.action_send_file: {
|
||||
if (MimeTypeUtil.isImage(singleFile) && !singleFile.isDown()) {
|
||||
mContainerActivity.getFileOperationsHelper().sendCachedImage(singleFile);
|
||||
return true;
|
||||
} else {
|
||||
// Obtain the file
|
||||
if (!singleFile.isDown()) { // Download the file
|
||||
Log_OC.d(TAG, singleFile.getRemotePath() + " : File must be downloaded");
|
||||
((FileDisplayActivity) mContainerActivity).startDownloadForSending(singleFile, DOWNLOAD_SEND);
|
||||
((FileDisplayActivity) mContainerActivity).startDownloadForSending(singleFile,
|
||||
DOWNLOAD_SEND);
|
||||
|
||||
} else {
|
||||
mContainerActivity.getFileOperationsHelper().sendDownloadedFile(singleFile);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
case R.id.action_set_as_wallpaper: {
|
||||
if (singleFile.isDown()) {
|
||||
mContainerActivity.getFileOperationsHelper().setPictureAs(singleFile);
|
||||
|
|
|
@ -44,6 +44,7 @@ import com.owncloud.android.lib.common.utils.Log_OC;
|
|||
import com.owncloud.android.lib.resources.shares.OCShare;
|
||||
import com.owncloud.android.lib.resources.shares.ShareType;
|
||||
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
|
||||
import com.owncloud.android.providers.DiskLruImageCacheFileProvider;
|
||||
import com.owncloud.android.services.OperationsService;
|
||||
import com.owncloud.android.services.observer.FileObserverService;
|
||||
import com.owncloud.android.ui.activity.FileActivity;
|
||||
|
@ -495,6 +496,21 @@ public class FileOperationsHelper {
|
|||
}
|
||||
}
|
||||
|
||||
public void sendCachedImage(OCFile file) {
|
||||
if (file != null) {
|
||||
Intent sendIntent = new Intent(Intent.ACTION_SEND);
|
||||
// set MimeType
|
||||
sendIntent.setType(file.getMimetype());
|
||||
sendIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("content://" + DiskLruImageCacheFileProvider.AUTHORITY +
|
||||
file.getRemotePath()));
|
||||
sendIntent.putExtra(Intent.ACTION_SEND, true); // Send Action
|
||||
|
||||
mFileActivity.startActivity(Intent.createChooser(sendIntent, "Send"));
|
||||
} else {
|
||||
Log_OC.wtf(TAG, "Trying to send a NULL OCFile");
|
||||
}
|
||||
}
|
||||
|
||||
public void setPictureAs(OCFile file) {
|
||||
if (file != null) {
|
||||
if (file.isDown()) {
|
||||
|
|
|
@ -31,6 +31,7 @@ public class ImageViewCustom extends AppCompatImageView {
|
|||
private long mMovieDuration;
|
||||
private long mMovieRunDuration;
|
||||
private long mLastTick;
|
||||
protected PreviewImageFragment previewImageFragment;
|
||||
|
||||
public ImageViewCustom(Context context) {
|
||||
super(context);
|
||||
|
@ -143,4 +144,7 @@ public class ImageViewCustom extends AppCompatImageView {
|
|||
}
|
||||
}
|
||||
|
||||
public void setPreviewImageFragment(PreviewImageFragment previewImageFragment) {
|
||||
this.previewImageFragment = previewImageFragment;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -149,7 +149,7 @@ public class PreviewImageActivity extends FileActivity implements
|
|||
}
|
||||
|
||||
mPreviewImagePagerAdapter = new PreviewImagePagerAdapter(getSupportFragmentManager(),
|
||||
parentFolder, getAccount(), getStorageManager(), MainApp.isOnlyOnDevice());
|
||||
parentFolder, getAccount(), getStorageManager(), MainApp.isOnlyOnDevice(), getBaseContext());
|
||||
}
|
||||
|
||||
mViewPager = (ExtendedViewPager) findViewById(R.id.fragmentPager);
|
||||
|
@ -323,7 +323,7 @@ public class PreviewImageActivity extends FileActivity implements
|
|||
finish();
|
||||
}
|
||||
|
||||
private void requestForDownload(OCFile file) {
|
||||
public void requestForDownload(OCFile file) {
|
||||
if (mDownloaderBinder == null) {
|
||||
Log_OC.d(TAG, "requestForDownload called without binder to download service");
|
||||
|
||||
|
@ -352,10 +352,6 @@ public class PreviewImageActivity extends FileActivity implements
|
|||
OCFile currentFile = mPreviewImagePagerAdapter.getFileAt(position);
|
||||
getSupportActionBar().setTitle(currentFile.getFileName());
|
||||
setDrawerIndicatorEnabled(false);
|
||||
if (!currentFile.isDown()
|
||||
&& !mPreviewImagePagerAdapter.pendingErrorAt(position)) {
|
||||
requestForDownload(currentFile);
|
||||
}
|
||||
|
||||
// Call to reset image zoom to initial state
|
||||
((PreviewImagePagerAdapter) mViewPager.getAdapter()).resetZoom();
|
||||
|
@ -454,6 +450,10 @@ public class PreviewImageActivity extends FileActivity implements
|
|||
}
|
||||
}
|
||||
|
||||
public void switchToFullScreen() {
|
||||
hideSystemUI(mFullScreenAnchorView);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAccountSet(boolean stateWasRecovered) {
|
||||
super.onAccountSet(stateWasRecovered);
|
||||
|
|
|
@ -36,6 +36,7 @@ import android.os.Process;
|
|||
import android.support.annotation.DrawableRes;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.StringRes;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.support.v4.app.FragmentStatePagerAdapter;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.LayoutInflater;
|
||||
|
@ -53,8 +54,10 @@ import android.widget.TextView;
|
|||
|
||||
import com.caverock.androidsvg.SVG;
|
||||
import com.caverock.androidsvg.SVGParseException;
|
||||
import com.owncloud.android.MainApp;
|
||||
import com.owncloud.android.R;
|
||||
import com.owncloud.android.datamodel.OCFile;
|
||||
import com.owncloud.android.datamodel.ThumbnailsCacheManager;
|
||||
import com.owncloud.android.files.FileMenuFilter;
|
||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
import com.owncloud.android.ui.dialog.ConfirmationDialogFragment;
|
||||
|
@ -88,7 +91,7 @@ public class PreviewImageFragment extends FileFragment {
|
|||
|
||||
private static final String ARG_FILE = "FILE";
|
||||
private static final String ARG_IGNORE_FIRST = "IGNORE_FIRST";
|
||||
|
||||
private static final String ARG_SHOW_RESIZED_IMAGE = "SHOW_RESIZED_IMAGE";
|
||||
private static final String SCREEN_NAME = "Image Preview";
|
||||
|
||||
private TouchImageViewCustom mImageView;
|
||||
|
@ -100,6 +103,8 @@ public class PreviewImageFragment extends FileFragment {
|
|||
protected ImageView mMultiListIcon;
|
||||
protected ProgressBar mMultiListProgress;
|
||||
|
||||
private Boolean mShowResizedImage = false;
|
||||
|
||||
public Bitmap mBitmap = null;
|
||||
|
||||
private static final String TAG = PreviewImageFragment.class.getSimpleName();
|
||||
|
@ -122,11 +127,14 @@ public class PreviewImageFragment extends FileFragment {
|
|||
* {@link FragmentStatePagerAdapter}
|
||||
* ; TODO better solution
|
||||
*/
|
||||
public static PreviewImageFragment newInstance(@NonNull OCFile imageFile, boolean ignoreFirstSavedState) {
|
||||
public static PreviewImageFragment newInstance(@NonNull OCFile imageFile, boolean ignoreFirstSavedState,
|
||||
boolean showResizedImage) {
|
||||
PreviewImageFragment frag = new PreviewImageFragment();
|
||||
frag.mShowResizedImage = showResizedImage;
|
||||
Bundle args = new Bundle();
|
||||
args.putParcelable(ARG_FILE, imageFile);
|
||||
args.putBoolean(ARG_IGNORE_FIRST, ignoreFirstSavedState);
|
||||
args.putBoolean(ARG_SHOW_RESIZED_IMAGE, showResizedImage);
|
||||
frag.setArguments(args);
|
||||
return frag;
|
||||
}
|
||||
|
@ -158,6 +166,7 @@ public class PreviewImageFragment extends FileFragment {
|
|||
// not right now
|
||||
|
||||
mIgnoreFirstSavedState = args.getBoolean(ARG_IGNORE_FIRST);
|
||||
mShowResizedImage = args.getBoolean(ARG_SHOW_RESIZED_IMAGE);
|
||||
setHasOptionsMenu(true);
|
||||
}
|
||||
|
||||
|
@ -171,6 +180,7 @@ public class PreviewImageFragment extends FileFragment {
|
|||
super.onCreateView(inflater, container, savedInstanceState);
|
||||
View view = inflater.inflate(R.layout.preview_image_fragment, container, false);
|
||||
mImageView = (TouchImageViewCustom) view.findViewById(R.id.image);
|
||||
mImageView.setPreviewImageFragment(this);
|
||||
mImageView.setVisibility(View.GONE);
|
||||
|
||||
view.setOnClickListener(new OnClickListener() {
|
||||
|
@ -197,6 +207,14 @@ public class PreviewImageFragment extends FileFragment {
|
|||
return view;
|
||||
}
|
||||
|
||||
public void switchToFullScreen() {
|
||||
((PreviewImageActivity) getActivity()).switchToFullScreen();
|
||||
}
|
||||
|
||||
public void downloadFile() {
|
||||
((PreviewImageActivity) getActivity()).requestForDownload(getFile());
|
||||
}
|
||||
|
||||
protected void setupMultiView(View view) {
|
||||
mMultiListContainer = (LinearLayout) view.findViewById(R.id.empty_list_view);
|
||||
mMultiListMessage = (TextView) view.findViewById(R.id.empty_list_view_text);
|
||||
|
@ -233,12 +251,64 @@ public class PreviewImageFragment extends FileFragment {
|
|||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
if (getFile() == null || !getFile().isDown()) {
|
||||
showErrorMessage(R.string.preview_image_error_no_local_file);
|
||||
if (getFile() != null) {
|
||||
mImageView.setTag(getFile().getFileId());
|
||||
|
||||
if (mShowResizedImage) {
|
||||
Bitmap resizedImage = ThumbnailsCacheManager.getBitmapFromDiskCache(
|
||||
String.valueOf(ThumbnailsCacheManager.PREFIX_RESIZED_IMAGE + getFile().getRemoteId()));
|
||||
|
||||
if (resizedImage != null && !getFile().needsUpdateThumbnail()) {
|
||||
mImageView.setImageBitmap(resizedImage);
|
||||
mImageView.setVisibility(View.VISIBLE);
|
||||
mBitmap = resizedImage;
|
||||
} else {
|
||||
// show thumbnail while loading resized image
|
||||
Bitmap thumbnail = ThumbnailsCacheManager.getBitmapFromDiskCache(
|
||||
String.valueOf(ThumbnailsCacheManager.PREFIX_THUMBNAIL + getFile().getRemoteId()));
|
||||
|
||||
if (thumbnail != null) {
|
||||
mImageView.setImageBitmap(thumbnail);
|
||||
mImageView.setVisibility(View.VISIBLE);
|
||||
mBitmap = thumbnail;
|
||||
} else {
|
||||
thumbnail = ThumbnailsCacheManager.mDefaultImg;
|
||||
}
|
||||
|
||||
// generate new resized image
|
||||
if (ThumbnailsCacheManager.cancelPotentialThumbnailWork(getFile(), mImageView) &&
|
||||
mContainerActivity.getStorageManager() != null) {
|
||||
final ThumbnailsCacheManager.ResizedImageGenerationTask task =
|
||||
new ThumbnailsCacheManager.ResizedImageGenerationTask(PreviewImageFragment.this,
|
||||
mImageView,
|
||||
mContainerActivity.getStorageManager(),
|
||||
mContainerActivity.getStorageManager().getAccount());
|
||||
if (resizedImage == null) {
|
||||
resizedImage = thumbnail;
|
||||
}
|
||||
final ThumbnailsCacheManager.AsyncResizedImageDrawable asyncDrawable =
|
||||
new ThumbnailsCacheManager.AsyncResizedImageDrawable(
|
||||
MainApp.getAppContext().getResources(),
|
||||
resizedImage,
|
||||
task
|
||||
);
|
||||
mImageView.setImageDrawable(asyncDrawable);
|
||||
task.execute(getFile());
|
||||
}
|
||||
}
|
||||
mMultiView.setVisibility(View.GONE);
|
||||
if (getResources() != null) {
|
||||
mImageView.setBackgroundColor(getResources().getColor(R.color.black));
|
||||
}
|
||||
mImageView.setVisibility(View.VISIBLE);
|
||||
|
||||
} else {
|
||||
mLoadBitmapTask = new LoadBitmapTask(mImageView);
|
||||
mLoadBitmapTask.execute(getFile());
|
||||
}
|
||||
} else {
|
||||
showErrorMessage(R.string.preview_image_error_no_local_file);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -368,9 +438,15 @@ public class PreviewImageFragment extends FileFragment {
|
|||
return true;
|
||||
|
||||
case R.id.action_send_file:
|
||||
if (MimeTypeUtil.isImage(getFile()) && !getFile().isDown()) {
|
||||
mContainerActivity.getFileOperationsHelper().sendCachedImage(getFile());
|
||||
return true;
|
||||
} else {
|
||||
mContainerActivity.getFileOperationsHelper().sendDownloadedFile(getFile());
|
||||
return true;
|
||||
}
|
||||
|
||||
case R.id.action_download_file:
|
||||
case R.id.action_sync_file:
|
||||
mContainerActivity.getFileOperationsHelper().syncFile(getFile());
|
||||
return true;
|
||||
|
@ -665,6 +741,24 @@ public class PreviewImageFragment extends FileFragment {
|
|||
}
|
||||
}
|
||||
|
||||
public void setErrorPreviewMessage() {
|
||||
Snackbar.make(mMultiView, R.string.resized_image_not_possible, Snackbar.LENGTH_INDEFINITE)
|
||||
.setAction(R.string.common_yes, new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
downloadFile();
|
||||
}
|
||||
}).show();
|
||||
}
|
||||
|
||||
public void setNoConnectionErrorMessage() {
|
||||
try {
|
||||
Snackbar.make(getView(), R.string.auth_no_net_conn_title, Snackbar.LENGTH_LONG).show();
|
||||
} catch (NullPointerException npe) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to test if an {@link OCFile} can be passed to a {@link PreviewImageFragment}
|
||||
* to be previewed.
|
||||
|
@ -691,6 +785,8 @@ public class PreviewImageFragment extends FileFragment {
|
|||
getFile().getMimetype().equalsIgnoreCase("image/svg+xml")) && getActivity() != null
|
||||
&& getActivity() instanceof PreviewImageActivity && getResources() != null) {
|
||||
PreviewImageActivity previewImageActivity = (PreviewImageActivity) getActivity();
|
||||
|
||||
if (mImageView.getDrawable() instanceof LayerDrawable) {
|
||||
LayerDrawable layerDrawable = (LayerDrawable) mImageView.getDrawable();
|
||||
Drawable layerOne;
|
||||
|
||||
|
@ -706,6 +802,7 @@ public class PreviewImageFragment extends FileFragment {
|
|||
mImageView.invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static int convertDpToPixel(float dp, Context context) {
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
package com.owncloud.android.ui.preview;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.content.Context;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.app.FragmentStatePagerAdapter;
|
||||
|
@ -50,6 +51,7 @@ public class PreviewImagePagerAdapter extends FragmentStatePagerAdapter {
|
|||
private Set<Integer> mObsoletePositions;
|
||||
private Set<Integer> mDownloadErrors;
|
||||
private FileDataStorageManager mStorageManager;
|
||||
private Context mContext;
|
||||
|
||||
private Map<Integer, FileFragment> mCachedFragments;
|
||||
|
||||
|
@ -63,7 +65,7 @@ public class PreviewImagePagerAdapter extends FragmentStatePagerAdapter {
|
|||
*/
|
||||
public PreviewImagePagerAdapter(FragmentManager fragmentManager, OCFile parentFolder,
|
||||
Account account, FileDataStorageManager storageManager,
|
||||
boolean onlyOnDevice) {
|
||||
boolean onlyOnDevice, Context context) {
|
||||
super(fragmentManager);
|
||||
|
||||
if (fragmentManager == null) {
|
||||
|
@ -76,6 +78,7 @@ public class PreviewImagePagerAdapter extends FragmentStatePagerAdapter {
|
|||
throw new IllegalArgumentException("NULL storage manager");
|
||||
}
|
||||
|
||||
mContext = context;
|
||||
mAccount = account;
|
||||
mStorageManager = storageManager;
|
||||
mImageFiles = mStorageManager.getFolderImages(parentFolder, onlyOnDevice);
|
||||
|
@ -140,16 +143,18 @@ public class PreviewImagePagerAdapter extends FragmentStatePagerAdapter {
|
|||
OCFile file = mImageFiles.get(i);
|
||||
Fragment fragment;
|
||||
if (file.isDown()) {
|
||||
fragment = PreviewImageFragment.newInstance(file, mObsoletePositions.contains(i));
|
||||
|
||||
} else if (mDownloadErrors.contains(i)) {
|
||||
fragment = FileDownloadFragment.newInstance(file, mAccount, true);
|
||||
((FileDownloadFragment)fragment).setError(true);
|
||||
mDownloadErrors.remove(i);
|
||||
fragment = PreviewImageFragment.newInstance(file, mObsoletePositions.contains(i), false);
|
||||
|
||||
} else {
|
||||
fragment = FileDownloadFragment.newInstance(file, mAccount, mObsoletePositions.contains(i));
|
||||
if (mDownloadErrors.contains(i)) {
|
||||
fragment = FileDownloadFragment.newInstance(file, mAccount, true);
|
||||
((FileDownloadFragment) fragment).setError(true);
|
||||
mDownloadErrors.remove(i);
|
||||
} else {
|
||||
fragment = PreviewImageFragment.newInstance(file, mObsoletePositions.contains(i), true);
|
||||
}
|
||||
}
|
||||
|
||||
mObsoletePositions.remove(i);
|
||||
return fragment;
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ import android.os.Build.VERSION;
|
|||
import android.os.Build.VERSION_CODES;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.GestureDetector;
|
||||
|
@ -35,6 +36,7 @@ import android.view.animation.AccelerateDecelerateInterpolator;
|
|||
import android.widget.OverScroller;
|
||||
import android.widget.Scroller;
|
||||
|
||||
import com.owncloud.android.R;
|
||||
import com.owncloud.android.ui.preview.ImageViewCustom;
|
||||
|
||||
/**
|
||||
|
@ -888,9 +890,13 @@ public class TouchImageViewCustom extends ImageViewCustom {
|
|||
*
|
||||
*/
|
||||
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
|
||||
private boolean snackShown = false;
|
||||
|
||||
@Override
|
||||
public boolean onScaleBegin(ScaleGestureDetector detector) {
|
||||
setState(State.ZOOM);
|
||||
|
||||
previewImageFragment.switchToFullScreen();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -898,6 +904,10 @@ public class TouchImageViewCustom extends ImageViewCustom {
|
|||
public boolean onScale(ScaleGestureDetector detector) {
|
||||
scaleImage(detector.getScaleFactor(), detector.getFocusX(), detector.getFocusY(), true);
|
||||
|
||||
if (!snackShown && getCurrentZoom() > 2 && !previewImageFragment.getFile().isDown()) {
|
||||
showDownloadSnackbar();
|
||||
}
|
||||
|
||||
//
|
||||
// OnTouchImageViewListener is set: TouchImageView pinch zoomed by user.
|
||||
//
|
||||
|
@ -907,6 +917,20 @@ public class TouchImageViewCustom extends ImageViewCustom {
|
|||
return true;
|
||||
}
|
||||
|
||||
private void showDownloadSnackbar() {
|
||||
snackShown = true;
|
||||
|
||||
Snackbar.make(getRootView(), R.string.resized_images_download_full_image, Snackbar.LENGTH_LONG)
|
||||
.setCallback(new Snackbar.Callback() {
|
||||
@Override
|
||||
public void onDismissed(Snackbar snackbar, int event) {
|
||||
super.onDismissed(snackbar, event);
|
||||
snackShown = false;
|
||||
}
|
||||
})
|
||||
.setAction(R.string.common_yes, v -> previewImageFragment.downloadFile()).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onScaleEnd(ScaleGestureDetector detector) {
|
||||
super.onScaleEnd(detector);
|
||||
|
|
|
@ -709,6 +709,10 @@
|
|||
<string name="push_notifications_old_login">No push notifications due to outdated login session. Please consider re-adding your account.</string>
|
||||
<string name="push_notifications_temp_error">Push notifications currently not available.</string>
|
||||
<string name="date_unknown">Unknown</string>
|
||||
|
||||
<string name="resized_image_not_possible">No resized image possible. Download full image?</string>
|
||||
<string name="resized_images_download_full_image">Download full image?</string>
|
||||
|
||||
<string name="store_short_desc">The Nextcloud Android app allows you to access all your files on your Nextcloud</string>
|
||||
<string name="store_full_desc">The Open Source Nextcloud Android app allows you to access all your files on your Nextcloud.\n\nFeatures:\n* Easy, modern interface, fully themed in alignment with your server\'s theming\n* Upload your files to your Nextcloud server\n* Share your files with others\n* Keep your favorite files and folders synced\n* Search across all folders on your server\n* Auto Upload for photos and videos taken by your device\n* Keep up to date with notifications\n* Multi-account support\n* Secure access to your data with fingerprint or pin\n* Integration with DAVdroid for easy setup of Calendar & Contacts synchronization\n\nPlease report all issues at https://github.com/nextcloud/android/issues and discuss this app at https://help.nextcloud.com/c/clients/android\n\nNew to Nextcloud? Nextcloud is a private file sync & share and communication server. It is fully open source and you can host it yourself or pay a company to do it for you. That way, you are in control of your photos, your calendar and contact data, your documents and everything else.\n\nCheck out Nextcloud at https://nextcloud.com</string>
|
||||
</resources>
|
||||
|
|
Loading…
Reference in a new issue