From: tobiasKaminsky Date: Wed, 1 Jul 2015 17:16:42 +0000 (+0200) Subject: Merge remote-tracking branch 'upstream/develop' into resizedImages X-Git-Tag: beta-20151122~1^2~9 X-Git-Url: http://git.linex4red.de/pub/Android/ownCloud.git/commitdiff_plain/ce35d6448e39f06d66596b23dc7e3ddf1e93ab5a?ds=inline;hp=-c Merge remote-tracking branch 'upstream/develop' into resizedImages --- ce35d6448e39f06d66596b23dc7e3ddf1e93ab5a diff --combined AndroidManifest.xml index 78cc8e81,2d989b1e..15db3df9 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@@ -124,16 -124,11 +124,16 @@@ android:name=".providers.FileContentProvider" android:authorities="@string/authority" android:enabled="true" - android:exported="false" + android:exported="true" android:label="@string/sync_string_files" android:syncable="true" > + + + - + diff --combined owncloud-android-library index 9e761387,f5fbca24..d5aa05bc --- a/owncloud-android-library +++ b/owncloud-android-library @@@ -1,1 -1,1 +1,1 @@@ - Subproject commit 9e761387a0b406402684571f28c36c2d6d2b6301 -Subproject commit f5fbca24becbb01660abe2a7013c1b536ea8a301 ++Subproject commit d5aa05bc0ca126626536e035459a33b13eeaf0fd diff --combined src/com/owncloud/android/datamodel/ThumbnailsCacheManager.java index a5ea5952,0e59a834..49bda88e --- a/src/com/owncloud/android/datamodel/ThumbnailsCacheManager.java +++ b/src/com/owncloud/android/datamodel/ThumbnailsCacheManager.java @@@ -22,36 -22,30 +22,37 @@@ package com.owncloud.android.datamodel; import java.io.File; + import java.io.InputStream; import java.lang.ref.WeakReference; import org.apache.commons.httpclient.HttpStatus; import org.apache.commons.httpclient.methods.GetMethod; 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.Point; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.media.ThumbnailUtils; import android.net.Uri; import android.os.AsyncTask; +import android.view.Display; +import android.view.View; +import android.view.WindowManager; import android.widget.ImageView; +import android.widget.ProgressBar; import com.owncloud.android.MainApp; import com.owncloud.android.R; + import com.owncloud.android.authentication.AccountUtils; import com.owncloud.android.lib.common.OwnCloudAccount; import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.OwnCloudClientManagerFactory; - import com.owncloud.android.lib.common.accounts.AccountUtils.Constants; import com.owncloud.android.lib.common.utils.Log_OC; import com.owncloud.android.lib.resources.status.OwnCloudVersion; import com.owncloud.android.ui.adapter.DiskLruImageCache; @@@ -66,8 -60,7 +67,7 @@@ public class ThumbnailsCacheManager private static final String TAG = ThumbnailsCacheManager.class.getSimpleName(); private static final String CACHE_FOLDER = "thumbnailCache"; - private static final String MINOR_SERVER_VERSION_FOR_THUMBS = "7.8.0"; - + private static final Object mThumbnailsDiskCacheLock = new Object(); private static DiskLruImageCache mThumbnailCache = null; private static boolean mThumbnailCacheStarting = true; @@@ -76,7 -69,6 +76,6 @@@ private static final CompressFormat mCompressFormat = CompressFormat.JPEG; private static final int mCompressQuality = 70; private static OwnCloudClient mClient = null; - private static String mServerVersion = null; public static Bitmap mDefaultImg = BitmapFactory.decodeResource( @@@ -135,10 -127,12 +134,12 @@@ while (mThumbnailCacheStarting) { try { mThumbnailsDiskCacheLock.wait(); - } catch (InterruptedException e) {} + } catch (InterruptedException e) { + Log_OC.e(TAG, "Wait in mThumbnailsDiskCacheLock was interrupted", e); + } } if (mThumbnailCache != null) { - return (Bitmap) mThumbnailCache.getBitmap(key); + return mThumbnailCache.getBitmap(key); } } return null; @@@ -146,12 -140,11 +147,12 @@@ public static class ThumbnailGenerationTask extends AsyncTask { private final WeakReference mImageViewReference; + private WeakReference mProgressWheelRef; private static Account mAccount; private Object mFile; + private Boolean mIsThumbnail; private FileDataStorageManager mStorageManager; - public ThumbnailGenerationTask(ImageView imageView, FileDataStorageManager storageManager, Account account) { // Use a WeakReference to ensure the ImageView can be garbage collected @@@ -162,12 -155,6 +163,12 @@@ mAccount = account; } + public ThumbnailGenerationTask(ImageView imageView, FileDataStorageManager storageManager, + Account account, ProgressBar progressWheel) { + this(imageView, storageManager, account); + mProgressWheelRef = new WeakReference(progressWheel); + } + public ThumbnailGenerationTask(ImageView imageView) { // Use a WeakReference to ensure the ImageView can be garbage collected mImageViewReference = new WeakReference(imageView); @@@ -179,9 -166,6 +180,6 @@@ try { if (mAccount != null) { - AccountManager accountMgr = AccountManager.get(MainApp.getAppContext()); - - mServerVersion = accountMgr.getUserData(mAccount, Constants.KEY_OC_VERSION); OwnCloudAccount ocAccount = new OwnCloudAccount(mAccount, MainApp.getAppContext()); mClient = OwnCloudClientManagerFactory.getDefaultSingleton(). @@@ -189,15 -173,12 +187,15 @@@ } mFile = params[0]; + mIsThumbnail = (Boolean) params[1]; + if (mFile instanceof OCFile) { - thumbnail = doOCFileInBackground(); + thumbnail = doOCFileInBackground(mIsThumbnail); } else if (mFile instanceof File) { - thumbnail = doFileInBackground(); - //} else { do nothing + thumbnail = doFileInBackground(mIsThumbnail); + } else { + // do nothing } }catch(Throwable t){ @@@ -216,25 -197,18 +214,25 @@@ bitmap = null; } - if (mImageViewReference != null && bitmap != null) { + if (bitmap != null) { final ImageView imageView = mImageViewReference.get(); final ThumbnailGenerationTask bitmapWorkerTask = getBitmapWorkerTask(imageView); - if (this == bitmapWorkerTask && imageView != null) { + if (this == bitmapWorkerTask) { String tagId = ""; if (mFile instanceof OCFile){ tagId = String.valueOf(((OCFile)mFile).getFileId()); } else if (mFile instanceof File){ - tagId = String.valueOf(((File)mFile).hashCode()); + tagId = String.valueOf(mFile.hashCode()); } if (String.valueOf(imageView.getTag()).equals(tagId)) { + if (mProgressWheelRef != null) { + final ProgressBar progressWheel = mProgressWheelRef.get(); + if (progressWheel != null) { + progressWheel.setVisibility(View.GONE); + } + } imageView.setImageBitmap(bitmap); + imageView.setVisibility(View.VISIBLE); } } } @@@ -245,13 -219,12 +243,13 @@@ * @param imageKey: thumb key * @param bitmap: image for extracting thumbnail * @param path: image path - * @param px: thumbnail dp + * @param pxW: thumbnail width + * @param pxH: thumbnail height * @return Bitmap */ - private Bitmap addThumbnailToCache(String imageKey, Bitmap bitmap, String path, int px){ + private 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); @@@ -269,52 -242,28 +267,52 @@@ private int getThumbnailDimension(){ // Converts dp to pixel Resources r = MainApp.getAppContext().getResources(); - return (int) Math.round(r.getDimension(R.dimen.file_icon_size_grid)); + return Math.round(r.getDimension(R.dimen.file_icon_size_grid)); } - private Bitmap doOCFileInBackground() { + private Point getScreenDimension(){ + WindowManager wm = (WindowManager) MainApp.getAppContext().getSystemService(Context.WINDOW_SERVICE); + Display display = wm.getDefaultDisplay(); + Point test = new Point(); + display.getSize(test); + return test; + } + + private Bitmap doOCFileInBackground(Boolean isThumbnail) { + Bitmap thumbnail = null; OCFile file = (OCFile)mFile; - final String imageKey = String.valueOf(file.getRemoteId()); + // distinguish between thumbnail and resized image + String temp = String.valueOf(file.getRemoteId()); + if (isThumbnail){ + temp = "t" + temp; + } else { + temp = "r" + temp; + } + + final String imageKey = temp; // 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 = 0; + int pxH = 0; + if (mIsThumbnail) { + pxW = pxH = getThumbnailDimension(); + } else { + Point p = getScreenDimension(); + pxW = p.x; + pxH = p.y; + } if (file.isDown()) { Bitmap bitmap = BitmapUtils.decodeSampledBitmapFromFile( - file.getStoragePath(), px, px); + file.getStoragePath(), pxW, pxH); if (bitmap != null) { - thumbnail = addThumbnailToCache(imageKey, bitmap, file.getStoragePath(), px); + thumbnail = addThumbnailToCache(imageKey, bitmap, file.getStoragePath(), pxW, pxH); file.setNeedsUpdateThumbnail(false); mStorageManager.saveFile(file); @@@ -322,38 -271,23 +320,42 @@@ } else { // Download thumbnail from server - if (mClient != null && mServerVersion != null) { - OwnCloudVersion serverOCVersion = new OwnCloudVersion(mServerVersion); - if (serverOCVersion.compareTo( - new OwnCloudVersion(MINOR_SERVER_VERSION_FOR_THUMBS)) >= 0) { + OwnCloudVersion serverOCVersion = AccountUtils.getServerVersion(mAccount); + if (mClient != null && serverOCVersion != null) { + if (serverOCVersion.supportsRemoteThumbnails()) { try { - int status = -1; - String uri = mClient.getBaseUri() + "" + "/index.php/apps/files/api/v1/thumbnail/" + - px + "/" + px + Uri.encode(file.getRemotePath(), "/"); + pxW + "/" + pxH + Uri.encode(file.getRemotePath(), "/"); Log_OC.d("Thumbnail", "URI: " + uri); GetMethod get = new GetMethod(uri); - status = mClient.executeMethod(get); + int status = mClient.executeMethod(get); if (status == HttpStatus.SC_OK) { + // byte[] bytes = get.getResponseBody(); + // Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, + // bytes.length); + InputStream inputStream = get.getResponseBodyAsStream(); + Bitmap bitmap = BitmapFactory.decodeStream(inputStream); - thumbnail = ThumbnailUtils.extractThumbnail(bitmap, px, px); ++ thumbnail = ThumbnailUtils.extractThumbnail(bitmap, pxW, pxH); + byte[] bytes = get.getResponseBody(); + + String type = ""; + if (mIsThumbnail){ + type = "Thumbnail"; + } else { + type = "Resized image"; + } - Log_OC.d("Thumbnail", type + " size of " + file.getRemotePath() + ": " + bytes.length); ++ Log_OC.d("Thumbnail", ++ type + " size of " + file.getRemotePath() ++ + ": " + bytes.length); + - Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, - bytes.length); ++ // bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length); + + if (mIsThumbnail) { + thumbnail = ThumbnailUtils.extractThumbnail(bitmap, pxW, pxH); + } else { + thumbnail = bitmap; + } // Add thumbnail to cache if (thumbnail != null) { @@@ -374,32 -308,24 +376,32 @@@ } - private Bitmap doFileInBackground() { + private Bitmap doFileInBackground(Boolean mIsThumbnail) { + Bitmap thumbnail = null; File file = (File)mFile; final String imageKey = String.valueOf(file.hashCode()); // Check disk cache in background thread - Bitmap thumbnail = getBitmapFromDiskCache(imageKey); + thumbnail = getBitmapFromDiskCache(imageKey); // Not found in disk cache if (thumbnail == null) { - - int px = getThumbnailDimension(); + int pxW = 0; + int pxH = 0; + if (mIsThumbnail) { + pxW = pxH = getThumbnailDimension(); + } else { + Point p = getScreenDimension(); + pxW = p.x; + pxH = p.y; + } Bitmap bitmap = BitmapUtils.decodeSampledBitmapFromFile( - file.getAbsolutePath(), px, px); + file.getAbsolutePath(), pxW, pxH); if (bitmap != null) { - thumbnail = addThumbnailToCache(imageKey, bitmap, file.getPath(), px); + thumbnail = addThumbnailToCache(imageKey, bitmap, file.getPath(), pxW, pxH); } } return thumbnail; diff --combined src/com/owncloud/android/files/FileOperationsHelper.java index bddeed02,75fae370..b5eeb614 --- a/src/com/owncloud/android/files/FileOperationsHelper.java +++ b/src/com/owncloud/android/files/FileOperationsHelper.java @@@ -24,36 -24,25 +24,35 @@@ package com.owncloud.android.files import org.apache.http.protocol.HTTP; import android.accounts.Account; - import android.accounts.AccountManager; import android.content.Intent; +import android.graphics.Bitmap; import android.net.Uri; import android.support.v4.app.DialogFragment; import android.webkit.MimeTypeMap; import android.widget.Toast; +import com.owncloud.android.MainApp; import com.owncloud.android.R; + import com.owncloud.android.authentication.AccountUtils; import com.owncloud.android.datamodel.OCFile; +import com.owncloud.android.datamodel.ThumbnailsCacheManager; import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder; import com.owncloud.android.files.services.FileUploader.FileUploaderBinder; - import com.owncloud.android.lib.common.accounts.AccountUtils.Constants; import com.owncloud.android.lib.common.network.WebdavUtils; import com.owncloud.android.lib.common.utils.Log_OC; import com.owncloud.android.lib.resources.status.OwnCloudVersion; import com.owncloud.android.services.OperationsService; import com.owncloud.android.ui.activity.FileActivity; +import com.owncloud.android.ui.adapter.DiskLruImageCacheFileProvider; import com.owncloud.android.ui.dialog.ShareLinkToDialog; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; + /** * */ @@@ -80,19 -69,25 +79,25 @@@ public class FileOperationsHelper Intent intentForSavedMimeType = new Intent(Intent.ACTION_VIEW); intentForSavedMimeType.setDataAndType(Uri.parse("file://"+ encodedStoragePath), file.getMimetype()); - intentForSavedMimeType.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); + intentForSavedMimeType.setFlags( + Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION + ); Intent intentForGuessedMimeType = null; if (storagePath.lastIndexOf('.') >= 0) { - String guessedMimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(storagePath.substring(storagePath.lastIndexOf('.') + 1)); + String guessedMimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension( + storagePath.substring(storagePath.lastIndexOf('.') + 1) + ); if (guessedMimeType != null && !guessedMimeType.equals(file.getMimetype())) { intentForGuessedMimeType = new Intent(Intent.ACTION_VIEW); intentForGuessedMimeType.setDataAndType(Uri.parse("file://"+ encodedStoragePath), guessedMimeType); - intentForGuessedMimeType.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); + intentForGuessedMimeType.setFlags( + Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION + ); } } - Intent chooserIntent = null; + Intent chooserIntent; if (intentForGuessedMimeType != null) { chooserIntent = Intent.createChooser(intentForGuessedMimeType, mFileActivity.getString(R.string.actionbar_open_with)); } else { @@@ -123,7 -118,9 +128,9 @@@ } else { // Show a Message - Toast t = Toast.makeText(mFileActivity, mFileActivity.getString(R.string.share_link_no_support_share_api), Toast.LENGTH_LONG); + Toast t = Toast.makeText( + mFileActivity, mFileActivity.getString(R.string.share_link_no_support_share_api), Toast.LENGTH_LONG + ); t.show(); } } @@@ -161,10 -158,8 +168,8 @@@ */ public boolean isSharedSupported() { if (mFileActivity.getAccount() != null) { - AccountManager accountManager = AccountManager.get(mFileActivity); - - String version = accountManager.getUserData(mFileActivity.getAccount(), Constants.KEY_OC_VERSION); - return (new OwnCloudVersion(version)).isSharedSupported(); + OwnCloudVersion serverVersion = AccountUtils.getServerVersion(mFileActivity.getAccount()); + return (serverVersion != null && serverVersion.isSharedSupported()); } return false; } @@@ -207,24 -202,6 +212,24 @@@ Log_OC.wtf(TAG, "Trying to send a NULL OCFile"); } } + + public void sendCachedImage(OCFile file) { + if (file != null) { + Intent sendIntent = new Intent(android.content.Intent.ACTION_SEND); + // set MimeType + sendIntent.setType(file.getMimetype()); +// sendIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("content://" + DiskLruImageCacheFileProvider.AUTHORITY + "/#" + file.getRemoteId() + "#" + file.getFileName())); + sendIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("content://" + DiskLruImageCacheFileProvider.AUTHORITY + file.getRemotePath())); + sendIntent.putExtra(Intent.ACTION_SEND, true); // Send Action + + // Show dialog, without the own app + String[] packagesToExclude = new String[] { mFileActivity.getPackageName() }; + DialogFragment chooserDialog = ShareLinkToDialog.newInstance(sendIntent, packagesToExclude, file); + chooserDialog.show(mFileActivity.getSupportFragmentManager(), FTAG_CHOOSER_DIALOG); + } else { + Log_OC.wtf(TAG, "Trying to send a NULL OCFile"); + } + } public void syncFile(OCFile file) { @@@ -344,5 -321,14 +349,14 @@@ mWaitingForOpId = waitingForOpId; } - + /** + * @return 'True' if the server doesn't need to check forbidden characters + */ + public boolean isVersionWithForbiddenCharacters() { + if (mFileActivity.getAccount() != null) { + OwnCloudVersion serverVersion = AccountUtils.getServerVersion(mFileActivity.getAccount()); + return (serverVersion != null && serverVersion.isVersionWithForbiddenCharacters()); + } + return false; + } } diff --combined src/com/owncloud/android/ui/adapter/FileListListAdapter.java index 5bc377af,c6ea0344..eb595383 --- a/src/com/owncloud/android/ui/adapter/FileListListAdapter.java +++ b/src/com/owncloud/android/ui/adapter/FileListListAdapter.java @@@ -158,17 -158,22 +158,22 @@@ public class FileListListAdapter extend viewType = ViewType.GRID_ITEM; } - // Create View - switch (viewType){ - case GRID_IMAGE: - view = inflator.inflate(R.layout.grid_image, null); - break; - case GRID_ITEM: - view = inflator.inflate(R.layout.grid_item, null); - break; - case LIST_ITEM: - view = inflator.inflate(R.layout.list_item, null); - break; + // create view only if differs, otherwise reuse + if (convertView == null || (convertView != null && convertView.getTag() != viewType)) { + switch (viewType) { + case GRID_IMAGE: + view = inflator.inflate(R.layout.grid_image, null); + view.setTag(ViewType.GRID_IMAGE); + break; + case GRID_ITEM: + view = inflator.inflate(R.layout.grid_item, null); + view.setTag(ViewType.GRID_ITEM); + break; + case LIST_ITEM: + view = inflator.inflate(R.layout.list_item, null); + view.setTag(ViewType.LIST_ITEM); + break; + } } view.invalidate(); @@@ -313,7 -318,7 +318,7 @@@ task ); fileIcon.setImageDrawable(asyncDrawable); - task.execute(file); + task.execute(file, true); } } } else { @@@ -402,14 -407,16 +407,16 @@@ * @param updatedStorageManager Optional updated storage manager; used to replace * mStorageManager if is different (and not NULL) */ - public void swapDirectory(OCFile directory, FileDataStorageManager updatedStorageManager) { + public void swapDirectory(OCFile directory, FileDataStorageManager updatedStorageManager + /*, boolean onlyOnDevice*/) { mFile = directory; if (updatedStorageManager != null && updatedStorageManager != mStorageManager) { mStorageManager = updatedStorageManager; mAccount = AccountUtils.getCurrentOwnCloudAccount(mContext); } if (mStorageManager != null) { - mFiles = mStorageManager.getFolderContent(mFile); + // TODO Enable when "On Device" is recovered ? + mFiles = mStorageManager.getFolderContent(mFile/*, onlyOnDevice*/); mFilesOrig.clear(); mFilesOrig.addAll(mFiles); diff --combined src/com/owncloud/android/ui/fragment/OCFileListFragment.java index ad320f55,68deb031..091549ae --- a/src/com/owncloud/android/ui/fragment/OCFileListFragment.java +++ b/src/com/owncloud/android/ui/fragment/OCFileListFragment.java @@@ -36,10 -36,13 +36,13 @@@ import android.widget.AdapterView import android.widget.AdapterView.AdapterContextMenuInfo; import com.owncloud.android.R; + import com.owncloud.android.authentication.AccountUtils; import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.files.FileMenuFilter; import com.owncloud.android.lib.common.utils.Log_OC; + import com.owncloud.android.lib.resources.status.OwnCloudVersion; + import com.owncloud.android.ui.activity.FileActivity; import com.owncloud.android.ui.activity.FileDisplayActivity; import com.owncloud.android.ui.activity.FolderPickerActivity; import com.owncloud.android.ui.activity.OnEnforceableRefreshListener; @@@ -54,7 -57,7 +57,7 @@@ import com.owncloud.android.utils.FileS /** * A Fragment that lists all files and folders in a given path. * - * TODO refactorize to get rid of direct dependency on FileDisplayActivity + * TODO refactor to get rid of direct dependency on FileDisplayActivity */ public class OCFileListFragment extends ExtendedListFragment { @@@ -68,8 -71,6 +71,6 @@@ private static final String KEY_FILE = MY_PACKAGE + ".extra.FILE"; - private final static Double THUMBNAIL_THRESHOLD = 0.5; - private FileFragment.ContainerActivity mContainerActivity; private OCFile mFile = null; @@@ -77,7 -78,8 +78,8 @@@ private boolean mJustFolders; private OCFile mTargetFile; - + + /** * {@inheritDoc} @@@ -132,7 -134,7 +134,7 @@@ mJustFolders = (args == null) ? false : args.getBoolean(ARG_JUST_FOLDERS, false); mAdapter = new FileListListAdapter( mJustFolders, - getSherlockActivity(), + getActivity(), mContainerActivity ); setListAdapter(mAdapter); @@@ -182,8 -184,9 +184,9 @@@ moveCount++; } // exit is granted because storageManager.getFileByPath("/") never returns null mFile = parentDir; - - listDirectory(mFile); + + // TODO Enable when "On Device" is recovered ? + listDirectory(mFile /*, MainApp.getOnlyOnDevice()*/); onRefresh(false); @@@ -201,7 -204,8 +204,8 @@@ if (file != null) { if (file.isFolder()) { // update state and view of this fragment - listDirectory(file); + // TODO Enable when "On Device" is recovered ? + listDirectory(file/*, MainApp.getOnlyOnDevice()*/); // then, notify parent activity to let it update its state and view mContainerActivity.onBrowsedDownTo(file); // save index and top position @@@ -220,7 -224,11 +224,7 @@@ mContainerActivity.getFileOperationsHelper().openFile(file); } - } else { - // automatic download, preview on finish - ((FileDisplayActivity)mContainerActivity).startDownloadForPreview(file); } - } } else { @@@ -240,7 -248,7 +244,7 @@@ boolean allowContextualActions = (args == null) ? true : args.getBoolean(ARG_ALLOW_CONTEXTUAL_ACTIONS, true); if (allowContextualActions) { - MenuInflater inflater = getSherlockActivity().getMenuInflater(); + MenuInflater inflater = getActivity().getMenuInflater(); inflater.inflate(R.menu.file_actions_menu, menu); AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo; OCFile targetFile = (OCFile) mAdapter.getItem(info.position); @@@ -250,14 -258,14 +254,14 @@@ targetFile, mContainerActivity.getStorageManager().getAccount(), mContainerActivity, - getSherlockActivity() + getActivity() ); mf.filter(menu); } /// TODO break this direct dependency on FileDisplayActivity... if possible MenuItem item = menu.findItem(R.id.action_open_file_with); - FileFragment frag = ((FileDisplayActivity)getSherlockActivity()).getSecondFragment(); + FileFragment frag = ((FileDisplayActivity)getActivity()).getSecondFragment(); if (frag != null && frag instanceof FileDetailFragment && frag.getFile().getFileId() == targetFile.getFileId()) { item = menu.findItem(R.id.action_see_details); @@@ -351,8 -359,15 +355,15 @@@ /** * Calls {@link OCFileListFragment#listDirectory(OCFile)} with a null parameter */ - public void listDirectory(){ + public void listDirectory(/*boolean onlyOnDevice*/){ listDirectory(null); + // TODO Enable when "On Device" is recovered ? + // listDirectory(null, onlyOnDevice); + } + + public void refreshDirectory(){ + // TODO Enable when "On Device" is recovered ? + listDirectory(getCurrentFile()/*, MainApp.getOnlyOnDevice()*/); } /** @@@ -362,7 -377,7 +373,7 @@@ * * @param directory File to be listed */ - public void listDirectory(OCFile directory) { + public void listDirectory(OCFile directory/*, boolean onlyOnDevice*/) { FileDataStorageManager storageManager = mContainerActivity.getStorageManager(); if (storageManager != null) { @@@ -383,7 -398,8 +394,8 @@@ directory = storageManager.getFileById(directory.getParentId()); } - mAdapter.swapDirectory(directory, storageManager); + // TODO Enable when "On Device" is recovered ? + mAdapter.swapDirectory(directory, storageManager/*, onlyOnDevice*/); if (mFile == null || !mFile.equals(directory)) { mCurrentListView.setSelection(0); } @@@ -414,7 -430,10 +426,10 @@@ setFooterText(generateFooterText(filesCount, foldersCount)); // decide grid vs list view - if (((double)imagesCount / (double)filesCount) >= THUMBNAIL_THRESHOLD) { + OwnCloudVersion version = AccountUtils.getServerVersion( + ((FileActivity)mContainerActivity).getAccount()); + if (version != null && version.supportsRemoteThumbnails() && + imagesCount > 0 && imagesCount == filesCount) { switchToGridView(); } else { switchToListView(); @@@ -455,5 -474,7 +470,7 @@@ public void sortBySize(boolean descending) { mAdapter.setSortOrder(FileStorageUtils.SORT_SIZE, descending); } - + + + } diff --combined src/com/owncloud/android/ui/preview/PreviewImageActivity.java index 7f4bfc39,2b0d96ce..bfb02d3b --- a/src/com/owncloud/android/ui/preview/PreviewImageActivity.java +++ b/src/com/owncloud/android/ui/preview/PreviewImageActivity.java @@@ -8,7 -8,7 +8,7 @@@ * it under the terms of the GNU General Public License version 2, * as published by the Free Software Foundation. * - * This program is distributed in the hope that it will be useful, + * This program is distributed in the hd 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. @@@ -26,19 -26,19 +26,19 @@@ import android.content.Context import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; - import android.content.SharedPreferences; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; - import android.preference.PreferenceManager; + import android.support.v4.view.GravityCompat; import android.support.v4.view.ViewPager; + import android.support.v4.widget.DrawerLayout; + import android.support.v7.app.ActionBar; + import android.view.MenuItem; import android.view.View; + import android.view.Window; - import com.actionbarsherlock.app.ActionBar; - import com.actionbarsherlock.view.MenuItem; - import com.actionbarsherlock.view.Window; import com.ortiz.touch.ExtendedViewPager; import com.owncloud.android.R; import com.owncloud.android.authentication.AccountUtils; @@@ -58,7 -58,6 +58,6 @@@ import com.owncloud.android.operations. import com.owncloud.android.operations.UnshareLinkOperation; import com.owncloud.android.ui.activity.FileActivity; import com.owncloud.android.ui.activity.FileDisplayActivity; - import com.owncloud.android.ui.activity.PinCodeActivity; import com.owncloud.android.ui.fragment.FileFragment; import com.owncloud.android.utils.DisplayUtils; @@@ -66,9 -65,9 +65,9 @@@ /** * Holds a swiping galley where image files contained in an ownCloud directory are shown */ - public class PreviewImageActivity extends FileActivity implements - FileFragment.ContainerActivity, - ViewPager.OnPageChangeListener, OnRemoteOperationListener { + public class PreviewImageActivity extends FileActivity implements + FileFragment.ContainerActivity, + ViewPager.OnPageChangeListener, OnRemoteOperationListener { public static final int DIALOG_SHORT_WAIT = 0; @@@ -90,23 -89,24 +89,24 @@@ private View mFullScreenAnchorView; - + @Override protected void onCreate(Bundle savedInstanceState) { + requestWindowFeature(Window.FEATURE_ACTION_BAR_OVERLAY); + super.onCreate(savedInstanceState); - requestWindowFeature(Window.FEATURE_ACTION_BAR_OVERLAY); setContentView(R.layout.preview_image_activity); - + + // Navigation Drawer + initDrawer(); + + // ActionBar ActionBar actionBar = getSupportActionBar(); actionBar.setIcon(DisplayUtils.getSeasonalIconId()); - actionBar.setDisplayHomeAsUpEnabled(true); + updateActionBarTitleAndHomeButton(null); actionBar.hide(); - - // PIN CODE request - if (getIntent().getExtras() != null && savedInstanceState == null && fromNotification()) { - requestPinCode(); - } + // Make sure we're running on Honeycomb or higher to use FullScreen and // Immersive Mode @@@ -115,7 -115,8 +115,8 @@@ mFullScreenAnchorView = getWindow().getDecorView(); // to keep our UI controls visibility in line with system bars // visibility - mFullScreenAnchorView.setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener() { + mFullScreenAnchorView.setOnSystemUiVisibilityChangeListener + (new View.OnSystemUiVisibilityChangeListener() { @SuppressLint("InlinedApi") @Override public void onSystemUiVisibilityChange(int flags) { @@@ -123,8 -124,10 +124,10 @@@ ActionBar actionBar = getSupportActionBar(); if (visible) { actionBar.show(); + mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED); } else { actionBar.hide(); + mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED); } } }); @@@ -141,21 -144,28 +144,28 @@@ private void initViewPager() { // get parent from path - String parentPath = getFile().getRemotePath().substring(0, getFile().getRemotePath().lastIndexOf(getFile().getFileName())); + String parentPath = getFile().getRemotePath().substring(0, + getFile().getRemotePath().lastIndexOf(getFile().getFileName())); OCFile parentFolder = getStorageManager().getFileByPath(parentPath); if (parentFolder == null) { // should not be necessary parentFolder = getStorageManager().getFileByPath(OCFile.ROOT_PATH); } - mPreviewImagePagerAdapter = new PreviewImagePagerAdapter(getSupportFragmentManager(), parentFolder, getAccount(), getStorageManager()); + + // TODO Enable when "On Device" is recovered ? + mPreviewImagePagerAdapter = new PreviewImagePagerAdapter(getSupportFragmentManager(), + parentFolder, getAccount(), getStorageManager()/*, MainApp.getOnlyOnDevice()*/); + mViewPager = (ExtendedViewPager) findViewById(R.id.fragmentPager); - int position = mHasSavedPosition ? mSavedPosition : mPreviewImagePagerAdapter.getFilePosition(getFile()); + int position = mHasSavedPosition ? mSavedPosition : + mPreviewImagePagerAdapter.getFilePosition(getFile()); position = (position >= 0) ? position : 0; mViewPager.setAdapter(mPreviewImagePagerAdapter); mViewPager.setOnPageChangeListener(this); mViewPager.setCurrentItem(position); if (position == 0 && !getFile().isDown()) { - // this is necessary because mViewPager.setCurrentItem(0) just after setting the adapter does not result in a call to #onPageSelected(0) + // this is necessary because mViewPager.setCurrentItem(0) just after setting the + // adapter does not result in a call to #onPageSelected(0) mRequestWaitingForBinder = true; } } @@@ -228,7 -238,8 +238,8 @@@ } - private void onUnshareLinkOperationFinish(UnshareLinkOperation operation, RemoteOperationResult result) { + private void onUnshareLinkOperationFinish(UnshareLinkOperation operation, + RemoteOperationResult result) { if (result.isSuccess()) { OCFile file = getStorageManager().getFileByPath(getFile().getRemotePath()); if (file != null) { @@@ -241,7 -252,8 +252,8 @@@ } - private void onCreateShareOperationFinish(CreateShareOperation operation, RemoteOperationResult result) { + private void onCreateShareOperationFinish(CreateShareOperation operation, + RemoteOperationResult result) { if (result.isSuccess()) { OCFile file = getStorageManager().getFileByPath(getFile().getRemotePath()); if (file != null) { @@@ -262,15 -274,18 +274,18 @@@ @Override public void onServiceConnected(ComponentName component, IBinder service) { - if (component.equals(new ComponentName(PreviewImageActivity.this, FileDownloader.class))) { + if (component.equals(new ComponentName(PreviewImageActivity.this, + FileDownloader.class))) { mDownloaderBinder = (FileDownloaderBinder) service; if (mRequestWaitingForBinder) { mRequestWaitingForBinder = false; - Log_OC.d(TAG, "Simulating reselection of current page after connection of download binder"); + Log_OC.d(TAG, "Simulating reselection of current page after connection " + + "of download binder"); onPageSelected(mViewPager.getCurrentItem()); } - } else if (component.equals(new ComponentName(PreviewImageActivity.this, FileUploader.class))) { + } else if (component.equals(new ComponentName(PreviewImageActivity.this, + FileUploader.class))) { Log_OC.d(TAG, "Upload service connected"); mUploaderBinder = (FileUploaderBinder) service; } else { @@@ -281,10 -296,12 +296,12 @@@ @Override public void onServiceDisconnected(ComponentName component) { - if (component.equals(new ComponentName(PreviewImageActivity.this, FileDownloader.class))) { + if (component.equals(new ComponentName(PreviewImageActivity.this, + FileDownloader.class))) { Log_OC.d(TAG, "Download service suddenly disconnected"); mDownloaderBinder = null; - } else if (component.equals(new ComponentName(PreviewImageActivity.this, FileUploader.class))) { + } else if (component.equals(new ComponentName(PreviewImageActivity.this, + FileUploader.class))) { Log_OC.d(TAG, "Upload service suddenly disconnected"); mUploaderBinder = null; } @@@ -309,7 -326,11 +326,11 @@@ switch(item.getItemId()){ case android.R.id.home: - backToDisplayActivity(); + if (mDrawerLayout.isDrawerOpen(GravityCompat.START)) { + mDrawerLayout.closeDrawer(GravityCompat.START); + } else { + backToDisplayActivity(); + } returnValue = true; break; default: @@@ -323,7 -344,7 +344,7 @@@ @Override protected void onResume() { super.onResume(); - //Log_OC.e(TAG, "ACTIVITY, ONRESUME"); + mDownloadFinishReceiver = new DownloadFinishReceiver(); IntentFilter filter = new IntentFilter(FileDownloader.getDownloadFinishMessage()); @@@ -333,14 -354,16 +354,16 @@@ @Override protected void onPostResume() { - //Log_OC.e(TAG, "ACTIVITY, ONPOSTRESUME"); super.onPostResume(); } @Override public void onPause() { - unregisterReceiver(mDownloadFinishReceiver); - mDownloadFinishReceiver = null; + if (mDownloadFinishReceiver != null){ + unregisterReceiver(mDownloadFinishReceiver); + mDownloadFinishReceiver = null; + } + super.onPause(); } @@@ -354,7 -377,8 +377,8 @@@ Intent showDetailsIntent = new Intent(this, FileDisplayActivity.class); showDetailsIntent.setAction(FileDisplayActivity.ACTION_DETAILS); showDetailsIntent.putExtra(FileActivity.EXTRA_FILE, file); - showDetailsIntent.putExtra(FileActivity.EXTRA_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(this)); + showDetailsIntent.putExtra(FileActivity.EXTRA_ACCOUNT, + AccountUtils.getCurrentOwnCloudAccount(this)); startActivity(showDetailsIntent); int pos = mPreviewImagePagerAdapter.getFilePosition(file); file = mPreviewImagePagerAdapter.getFileAt(pos); @@@ -375,9 -399,10 +399,10 @@@ } /** - * This method will be invoked when a new page becomes selected. Animation is not necessarily complete. + * This method will be invoked when a new page becomes selected. Animation is not necessarily + * complete. * - * @param Position Position index of the new selected page + * @param position Position index of the new selected page */ @Override public void onPageSelected(int position) { @@@ -389,7 -414,13 +414,8 @@@ } else { OCFile currentFile = mPreviewImagePagerAdapter.getFileAt(position); getSupportActionBar().setTitle(currentFile.getFileName()); - + mDrawerToggle.setDrawerIndicatorEnabled(false); - if (!currentFile.isDown()) { - if (!mPreviewImagePagerAdapter.pendingErrorAt(position)) { - requestForDownload(currentFile); - } - } - ++ // Call to reset image zoom to initial state ((PreviewImagePagerAdapter) mViewPager.getAdapter()).resetZoom(); } @@@ -400,20 -431,22 +426,22 @@@ * Called when the scroll state changes. Useful for discovering when the user begins dragging, * when the pager is automatically settling to the current page. when it is fully stopped/idle. * - * @param State The new scroll state (SCROLL_STATE_IDLE, _DRAGGING, _SETTLING + * @param state The new scroll state (SCROLL_STATE_IDLE, _DRAGGING, _SETTLING */ @Override public void onPageScrollStateChanged(int state) { } /** - * This method will be invoked when the current page is scrolled, either as part of a programmatically - * initiated smooth scroll or a user initiated touch scroll. + * This method will be invoked when the current page is scrolled, either as part of a + * programmatically initiated smooth scroll or a user initiated touch scroll. * * @param position Position index of the first page currently being displayed. - * Page position+1 will be visible if positionOffset is nonzero. + * Page position+1 will be visible if positionOffset is + * nonzero. * - * @param positionOffset Value from [0, 1) indicating the offset from the page at position. + * @param positionOffset Value from [0, 1) indicating the offset from the page + * at position. * @param positionOffsetPixels Value in pixels indicating the offset from position. */ @Override @@@ -437,17 -470,21 +465,21 @@@ OCFile file = getStorageManager().getFileByPath(downloadedRemotePath); int position = mPreviewImagePagerAdapter.getFilePosition(file); - boolean downloadWasFine = intent.getBooleanExtra(FileDownloader.EXTRA_DOWNLOAD_RESULT, false); - //boolean isOffscreen = Math.abs((mViewPager.getCurrentItem() - position)) <= mViewPager.getOffscreenPageLimit(); + boolean downloadWasFine = intent.getBooleanExtra( + FileDownloader.EXTRA_DOWNLOAD_RESULT, false); + //boolean isOffscreen = Math.abs((mViewPager.getCurrentItem() - position)) + // <= mViewPager.getOffscreenPageLimit(); - if (position >= 0 && intent.getAction().equals(FileDownloader.getDownloadFinishMessage())) { + if (position >= 0 && + intent.getAction().equals(FileDownloader.getDownloadFinishMessage())) { if (downloadWasFine) { mPreviewImagePagerAdapter.updateFile(position, file); } else { mPreviewImagePagerAdapter.updateWithDownloadError(position); } - mPreviewImagePagerAdapter.notifyDataSetChanged(); // will trigger the creation of new fragments + mPreviewImagePagerAdapter.notifyDataSetChanged(); // will trigger the creation + // of new fragments } else { Log_OC.d(TAG, "Download finished, but the fragment is offscreen"); @@@ -482,9 -519,11 +514,11 @@@ ActionBar actionBar = getSupportActionBar(); if (!actionBar.isShowing()) { actionBar.show(); + mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED); } else { actionBar.hide(); + mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED); } @@@ -522,21 -561,6 +556,6 @@@ } } } - - - /** - * Launch an intent to request the PIN code to the user before letting him use the app - */ - private void requestPinCode() { - boolean pinStart = false; - SharedPreferences appPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); - pinStart = appPrefs.getBoolean("set_pincode", false); - if (pinStart) { - Intent i = new Intent(getApplicationContext(), PinCodeActivity.class); - i.putExtra(PinCodeActivity.EXTRA_ACTIVITY, "PreviewImageActivity"); - startActivity(i); - } - } @Override public void onBrowsedDownTo(OCFile folder) { @@@ -584,4 -608,9 +603,9 @@@ return false; } + @Override + public void allFilesOption(){ + backToDisplayActivity(); + super.allFilesOption(); + } } diff --combined src/com/owncloud/android/ui/preview/PreviewImageFragment.java index 581526c3,7950ec98..bb33a9c6 --- a/src/com/owncloud/android/ui/preview/PreviewImageFragment.java +++ b/src/com/owncloud/android/ui/preview/PreviewImageFragment.java @@@ -19,26 -19,20 +19,20 @@@ */ package com.owncloud.android.ui.preview; - import java.io.BufferedInputStream; - import java.io.File; - import java.io.FileInputStream; - import java.io.FilterInputStream; - import java.io.IOException; - import java.io.InputStream; import java.lang.ref.WeakReference; import android.accounts.Account; import android.annotation.SuppressLint; import android.app.Activity; import android.graphics.Bitmap; - import android.graphics.BitmapFactory; - import android.graphics.BitmapFactory.Options; import android.graphics.Point; import android.os.AsyncTask; import android.os.Bundle; import android.support.v4.app.FragmentStatePagerAdapter; - import android.view.Display; import android.view.LayoutInflater; + import android.view.Menu; + import android.view.MenuInflater; + import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; @@@ -46,43 -40,39 +40,43 @@@ import android.widget.ImageView import android.widget.ProgressBar; import android.widget.TextView; - import com.actionbarsherlock.view.Menu; - import com.actionbarsherlock.view.MenuInflater; - import com.actionbarsherlock.view.MenuItem; +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; import com.owncloud.android.ui.dialog.RemoveFileDialogFragment; import com.owncloud.android.ui.fragment.FileFragment; import com.owncloud.android.utils.BitmapUtils; + import com.owncloud.android.utils.DisplayUtils; import third_parties.michaelOrtiz.TouchImageViewCustom; /** * This fragment shows a preview of a downloaded image. + * + * Trying to get an instance with a NULL {@link OCFile} will produce an + * {@link IllegalStateException}. * - * Trying to get an instance with NULL {@link OCFile} or ownCloud {@link Account} values will produce an {@link IllegalStateException}. - * - * If the {@link OCFile} passed is not downloaded, an {@link IllegalStateException} is generated on instantiation too. + * If the {@link OCFile} passed is not downloaded, an {@link IllegalStateException} is generated on + * instantiation too. */ public class PreviewImageFragment extends FileFragment { public static final String EXTRA_FILE = "FILE"; - public static final String EXTRA_ACCOUNT = "ACCOUNT"; - private View mView; - private Account mAccount; + private static final String ARG_FILE = "FILE"; + private static final String ARG_IGNORE_FIRST = "IGNORE_FIRST"; + private TouchImageViewCustom mImageView; private TextView mMessageView; private ProgressBar mProgressWheel; + private Boolean mShowResizedImage = false; + public Bitmap mBitmap = null; private static final String TAG = PreviewImageFragment.class.getSimpleName(); @@@ -91,34 -81,42 +85,44 @@@ private LoadBitmapTask mLoadBitmapTask = null; - + /** - * Creates a fragment to preview an image. - * - * When 'imageFile' or 'ocAccount' are null - * - * @param fileToDetail An {@link OCFile} to preview as an image in the fragment - * @param ocAccount An ownCloud account; needed to start downloads - * @param ignoreFirstSavedState Flag to work around an unexpected behaviour of {@link FragmentStatePagerAdapter}; TODO better solution + * Public factory method to create a new fragment that previews an image. + * + * Android strongly recommends keep the empty constructor of fragments as the only public + * constructor, and + * use {@link #setArguments(Bundle)} to set the needed arguments. + * + * This method hides to client objects the need of doing the construction in two steps. + * + * @param imageFile An {@link OCFile} to preview as an image in the fragment + * @param ignoreFirstSavedState Flag to work around an unexpected behaviour of + * {@link FragmentStatePagerAdapter} + * ; TODO better solution */ - public PreviewImageFragment(OCFile fileToDetail, Account ocAccount, boolean ignoreFirstSavedState, boolean showResizedImage) { - super(fileToDetail); - mAccount = ocAccount; - mShowResizedImage = showResizedImage; - mIgnoreFirstSavedState = ignoreFirstSavedState; - public static PreviewImageFragment newInstance(OCFile imageFile, boolean ignoreFirstSavedState){ ++ public static PreviewImageFragment newInstance(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); + frag.setArguments(args); + return frag; } + /** * Creates an empty fragment for image previews. * - * MUST BE KEPT: the system uses it when tries to reinstantiate a fragment automatically (for instance, when the device is turned a aside). + * MUST BE KEPT: the system uses it when tries to reinstantiate a fragment automatically + * (for instance, when the device is turned a aside). * - * DO NOT CALL IT: an {@link OCFile} and {@link Account} must be provided for a successful construction + * DO NOT CALL IT: an {@link OCFile} and {@link Account} must be provided for a successful + * construction */ public PreviewImageFragment() { - super(); - mAccount = null; mIgnoreFirstSavedState = false; } @@@ -129,6 -127,12 +133,12 @@@ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + Bundle args = getArguments(); + setFile((OCFile)args.getParcelable(ARG_FILE)); + // TODO better in super, but needs to check ALL the class extending FileFragment; + // not right now + + mIgnoreFirstSavedState = args.getBoolean(ARG_IGNORE_FIRST); setHasOptionsMenu(true); } @@@ -140,8 -144,8 +150,8 @@@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { super.onCreateView(inflater, container, savedInstanceState); - mView = inflater.inflate(R.layout.preview_image_fragment, container, false); - mImageView = (TouchImageViewCustom) mView.findViewById(R.id.image); + View view = inflater.inflate(R.layout.preview_image_fragment, container, false); + mImageView = (TouchImageViewCustom) view.findViewById(R.id.image); mImageView.setVisibility(View.GONE); mImageView.setOnClickListener(new OnClickListener() { @Override @@@ -150,11 -154,11 +160,11 @@@ } }); - mMessageView = (TextView)mView.findViewById(R.id.message); + mMessageView = (TextView)view.findViewById(R.id.message); mMessageView.setVisibility(View.GONE); - mProgressWheel = (ProgressBar)mView.findViewById(R.id.progressWheel); + mProgressWheel = (ProgressBar)view.findViewById(R.id.progressWheel); mProgressWheel.setVisibility(View.VISIBLE); - return mView; + return view; } /** @@@ -165,9 -169,8 +175,8 @@@ super.onActivityCreated(savedInstanceState); if (savedInstanceState != null) { if (!mIgnoreFirstSavedState) { - OCFile file = (OCFile)savedInstanceState.getParcelable(PreviewImageFragment.EXTRA_FILE); + OCFile file = savedInstanceState.getParcelable(PreviewImageFragment.EXTRA_FILE); setFile(file); - mAccount = savedInstanceState.getParcelable(PreviewImageFragment.EXTRA_ACCOUNT); } else { mIgnoreFirstSavedState = false; } @@@ -175,9 -178,9 +184,6 @@@ if (getFile() == null) { throw new IllegalStateException("Instanced with a NULL OCFile"); } - if (mAccount == null) { - throw new IllegalStateException("Instanced with a NULL ownCloud Account"); - if (!getFile().isDown()) { - throw new IllegalStateException("There is no local file to preview"); -- } } @@@ -188,7 -191,6 +194,6 @@@ public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putParcelable(PreviewImageFragment.EXTRA_FILE, getFile()); - outState.putParcelable(PreviewImageFragment.EXTRA_ACCOUNT, mAccount); } @@@ -196,55 -198,21 +201,55 @@@ public void onStart() { super.onStart(); if (getFile() != null) { - mLoadBitmapTask = new LoadBitmapTask(mImageView, mMessageView, mProgressWheel); - //mLoadBitmapTask.execute(new String[]{getFile().getStoragePath()}); - mLoadBitmapTask.execute(getFile().getStoragePath()); + mImageView.setTag(getFile().getFileId()); + + if (mShowResizedImage){ + Bitmap thumbnail = ThumbnailsCacheManager.getBitmapFromDiskCache( + String.valueOf("r" + getFile().getRemoteId()) + ); + + if (thumbnail != null && !getFile().needsUpdateThumbnail()){ + mProgressWheel.setVisibility(View.GONE); + mImageView.setImageBitmap(thumbnail); - mImageView.setBitmap(thumbnail); + mImageView.setVisibility(View.VISIBLE); + mBitmap = thumbnail; + } else { + // generate new Thumbnail + if (ThumbnailsCacheManager.cancelPotentialWork(getFile(), mImageView)) { + final ThumbnailsCacheManager.ThumbnailGenerationTask task = + new ThumbnailsCacheManager.ThumbnailGenerationTask( - mImageView, mContainerActivity.getStorageManager(), mAccount, mProgressWheel - ); ++ mImageView, mContainerActivity.getStorageManager(), ++ mContainerActivity.getStorageManager().getAccount(), ++ mProgressWheel); + if (thumbnail == null) { + thumbnail = ThumbnailsCacheManager.mDefaultImg; + } + final ThumbnailsCacheManager.AsyncDrawable asyncDrawable = + new ThumbnailsCacheManager.AsyncDrawable( + MainApp.getAppContext().getResources(), + thumbnail, + task + ); + mImageView.setImageDrawable(asyncDrawable); + task.execute(getFile(), false); + } + } + } else { + mLoadBitmapTask = new LoadBitmapTask(mImageView, mMessageView, mProgressWheel); - mLoadBitmapTask.execute(new String[]{getFile().getStoragePath()}); ++ mLoadBitmapTask.execute(getFile().getStoragePath()); + } } } @Override public void onStop() { - super.onStop(); + Log_OC.d(TAG, "onStop starts"); if (mLoadBitmapTask != null) { mLoadBitmapTask.cancel(true); mLoadBitmapTask = null; } - + super.onStop(); } /** @@@ -271,7 -239,7 +276,7 @@@ getFile(), mContainerActivity.getStorageManager().getAccount(), mContainerActivity, - getSherlockActivity() + getActivity() ); mf.filter(menu); } @@@ -331,13 -299,8 +336,13 @@@ return true; } case R.id.action_send_file: { - mContainerActivity.getFileOperationsHelper().sendDownloadedFile(getFile()); - return true; + if (getFile().isImage() && !getFile().isDown()){ + mContainerActivity.getFileOperationsHelper().sendCachedImage(getFile()); + return true; + } else { + mContainerActivity.getFileOperationsHelper().sendDownloadedFile(getFile()); + return true; + } } case R.id.action_sync_file: { mContainerActivity.getFileOperationsHelper().syncFile(getFile()); @@@ -371,6 -334,9 +376,9 @@@ if (mBitmap != null) { mBitmap.recycle(); System.gc(); + // putting this in onStop() is just the same; the fragment is always destroyed by + // {@link FragmentStatePagerAdapter} when the fragment in swiped further than the + // valid offscreen distance, and onStop() is never called before than that } super.onDestroy(); } @@@ -389,15 -355,17 +397,17 @@@ /** * Weak reference to the target {@link ImageView} where the bitmap will be loaded into. - * - * Using a weak reference will avoid memory leaks if the target ImageView is retired from memory before the load finishes. + * + * Using a weak reference will avoid memory leaks if the target ImageView is retired from + * memory before the load finishes. */ private final WeakReference mImageViewRef; /** * Weak reference to the target {@link TextView} where error messages will be written. - * - * Using a weak reference will avoid memory leaks if the target ImageView is retired from memory before the load finishes. + * + * Using a weak reference will avoid memory leaks if the target ImageView is retired from + * memory before the load finishes. */ private final WeakReference mMessageViewRef; @@@ -405,7 -373,8 +415,8 @@@ /** * Weak reference to the target {@link ProgressBar} shown while the load is in progress. * - * Using a weak reference will avoid memory leaks if the target ImageView is retired from memory before the load finishes. + * Using a weak reference will avoid memory leaks if the target ImageView is retired from + * memory before the load finishes. */ private final WeakReference mProgressWheelRef; @@@ -421,7 -390,8 +432,8 @@@ * * @param imageView Target {@link ImageView} where the bitmap will be loaded into. */ - public LoadBitmapTask(ImageViewCustom imageView, TextView messageView, ProgressBar progressWheel) { + public LoadBitmapTask(ImageViewCustom imageView, TextView messageView, + ProgressBar progressWheel) { mImageViewRef = new WeakReference(imageView); mMessageViewRef = new WeakReference(messageView); mProgressWheelRef = new WeakReference(progressWheel); @@@ -431,47 -401,50 +443,50 @@@ @Override protected Bitmap doInBackground(String... params) { Bitmap result = null; - if (params.length != 1) return result; + if (params.length != 1) return null; String storagePath = params[0]; try { - if (isCancelled()) return result; - - File picture = new File(storagePath); - - if (picture != null) { - // Decode file into a bitmap in real size for being able to make zoom on - // the image - result = BitmapFactory.decodeStream(new FlushedInputStream - (new BufferedInputStream(new FileInputStream(picture)))); - } + int maxDownScale = 3; // could be a parameter passed to doInBackground(...) + Point screenSize = DisplayUtils.getScreenSize(getActivity()); + int minWidth = screenSize.x; + int minHeight = screenSize.y; + for (int i = 0; i < maxDownScale && result == null; i++) { + if (isCancelled()) return null; + try { + result = BitmapUtils.decodeSampledBitmapFromFile(storagePath, minWidth, + minHeight); + + if (isCancelled()) return result; + + if (result == null) { + mErrorMessageId = R.string.preview_image_error_unknown_format; + Log_OC.e(TAG, "File could not be loaded as a bitmap: " + storagePath); + break; + } else { + // Rotate image, obeying exif tag. + result = BitmapUtils.rotateImage(result, storagePath); + } - if (isCancelled()) return result; - - if (result == null) { - mErrorMessageId = R.string.preview_image_error_unknown_format; - Log_OC.e(TAG, "File could not be loaded as a bitmap: " + storagePath); - } else { - // Rotate image, obeying exif tag. - result = BitmapUtils.rotateImage(result, storagePath); + } catch (OutOfMemoryError e) { + mErrorMessageId = R.string.common_error_out_memory; + if (i < maxDownScale - 1) { + Log_OC.w(TAG, "Out of memory rendering file " + storagePath + + " ; scaling down"); + minWidth = minWidth / 2; + minHeight = minHeight / 2; + + } else { + Log_OC.w(TAG, "Out of memory rendering file " + storagePath + + " ; failing"); + } + if (result != null) { + result.recycle(); + } + result = null; + } } - - } catch (OutOfMemoryError e) { - Log_OC.e(TAG, "Out of memory occured for file " + storagePath, e); - if (isCancelled()) return result; - - // If out of memory error when loading or rotating image, try to load it scaled - result = loadScaledImage(storagePath); - - if (result == null) { - mErrorMessageId = R.string.preview_image_error_unknown_format; - Log_OC.e(TAG, "File could not be loaded as a bitmap: " + storagePath); - } else { - // Rotate scaled image, obeying exif tag - result = BitmapUtils.rotateImage(result, storagePath); - } - } catch (NoSuchFieldError e) { mErrorMessageId = R.string.common_error_unknown; Log_OC.e(TAG, "Error from access to unexisting field despite protection; file " @@@ -501,57 -474,55 +516,55 @@@ } else { showErrorMessage(); } + if (result != null && mBitmap != result) { + // unused bitmap, release it! (just in case) + result.recycle(); + } } @SuppressLint("InlinedApi") private void showLoadedImage(Bitmap result) { - if (mImageViewRef != null) { - final ImageViewCustom imageView = mImageViewRef.get(); - if (imageView != null) { - imageView.setBitmap(result); - imageView.setImageBitmap(result); - imageView.setVisibility(View.VISIBLE); - mBitmap = result; - } // else , silently finish, the fragment was destroyed - } - if (mMessageViewRef != null) { - final TextView messageView = mMessageViewRef.get(); - if (messageView != null) { - messageView.setVisibility(View.GONE); - } // else , silently finish, the fragment was destroyed + final ImageViewCustom imageView = mImageViewRef.get(); + if (imageView != null) { + Log_OC.d(TAG, "Showing image with resolution " + result.getWidth() + "x" + + result.getHeight()); + imageView.setImageBitmap(result); + imageView.setVisibility(View.VISIBLE); + mBitmap = result; // needs to be kept for recycling when not useful } + + final TextView messageView = mMessageViewRef.get(); + if (messageView != null) { + messageView.setVisibility(View.GONE); + } // else , silently finish, the fragment was destroyed } private void showErrorMessage() { - if (mImageViewRef != null) { - final ImageView imageView = mImageViewRef.get(); - if (imageView != null) { - // shows the default error icon - imageView.setVisibility(View.VISIBLE); - } // else , silently finish, the fragment was destroyed - } - if (mMessageViewRef != null) { - final TextView messageView = mMessageViewRef.get(); - if (messageView != null) { - messageView.setText(mErrorMessageId); - messageView.setVisibility(View.VISIBLE); - } // else , silently finish, the fragment was destroyed - } + final ImageView imageView = mImageViewRef.get(); + if (imageView != null) { + // shows the default error icon + imageView.setVisibility(View.VISIBLE); + } // else , silently finish, the fragment was destroyed + + final TextView messageView = mMessageViewRef.get(); + if (messageView != null) { + messageView.setText(mErrorMessageId); + messageView.setVisibility(View.VISIBLE); + } // else , silently finish, the fragment was destroyed } private void hideProgressWheel() { - if (mProgressWheelRef != null) { - final ProgressBar progressWheel = mProgressWheelRef.get(); - if (progressWheel != null) { - progressWheel.setVisibility(View.GONE); - } + final ProgressBar progressWheel = mProgressWheelRef.get(); + if (progressWheel != null) { + progressWheel.setVisibility(View.GONE); } } } /** - * Helper method to test if an {@link OCFile} can be passed to a {@link PreviewImageFragment} to be previewed. + * Helper method to test if an {@link OCFile} can be passed to a {@link PreviewImageFragment} + * to be previewed. * * @param file File to test if can be previewed. * @return 'True' if the file can be handled by the fragment. @@@ -573,83 -544,4 +586,4 @@@ return mImageView; } - static class FlushedInputStream extends FilterInputStream { - public FlushedInputStream(InputStream inputStream) { - super(inputStream); - } - - @Override - public long skip(long n) throws IOException { - long totalBytesSkipped = 0L; - while (totalBytesSkipped < n) { - long bytesSkipped = in.skip(n - totalBytesSkipped); - if (bytesSkipped == 0L) { - int byteValue = read(); - if (byteValue < 0) { - break; // we reached EOF - } else { - bytesSkipped = 1; // we read one byte - } - } - totalBytesSkipped += bytesSkipped; - } - return totalBytesSkipped; - } - } - - /** - * Load image scaled - * @param storagePath: path of the image - * @return Bitmap - */ - @SuppressWarnings("deprecation") - private Bitmap loadScaledImage(String storagePath) { - - Log_OC.d(TAG, "Loading image scaled"); - - // set desired options that will affect the size of the bitmap - BitmapFactory.Options options = new Options(); - options.inScaled = true; - options.inPurgeable = true; - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.GINGERBREAD_MR1) { - options.inPreferQualityOverSpeed = false; - } - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) { - options.inMutable = false; - } - // make a false load of the bitmap - just to be able to read outWidth, outHeight and outMimeType - options.inJustDecodeBounds = true; - BitmapFactory.decodeFile(storagePath, options); - - int width = options.outWidth; - int height = options.outHeight; - int scale = 1; - - Display display = getActivity().getWindowManager().getDefaultDisplay(); - Point size = new Point(); - int screenWidth; - int screenHeight; - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB_MR2) { - display.getSize(size); - screenWidth = size.x; - screenHeight = size.y; - } else { - screenWidth = display.getWidth(); - screenHeight = display.getHeight(); - } - - if (width > screenWidth) { - // second try to scale down the image , this time depending upon the screen size - scale = (int) Math.floor((float)width / screenWidth); - } - if (height > screenHeight) { - scale = Math.max(scale, (int) Math.floor((float)height / screenHeight)); - } - options.inSampleSize = scale; - - // really load the bitmap - options.inJustDecodeBounds = false; // the next decodeFile call will be real - return BitmapFactory.decodeFile(storagePath, options); - - } } diff --combined src/com/owncloud/android/ui/preview/PreviewImagePagerAdapter.java index 7a4eb22d,dda7dda2..d6ea3479 --- a/src/com/owncloud/android/ui/preview/PreviewImagePagerAdapter.java +++ b/src/com/owncloud/android/ui/preview/PreviewImagePagerAdapter.java @@@ -19,8 -19,6 +19,6 @@@ */ package com.owncloud.android.ui.preview; - import java.util.Collections; - import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@@ -29,7 -27,6 +27,7 @@@ import java.util.Set import java.util.Vector; import android.accounts.Account; +import android.graphics.Bitmap; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentStatePagerAdapter; @@@ -37,8 -34,6 +35,8 @@@ import android.view.ViewGroup import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; +import com.owncloud.android.datamodel.ThumbnailsCacheManager; +import com.owncloud.android.ui.adapter.FileListListAdapter; import com.owncloud.android.ui.fragment.FileFragment; import com.owncloud.android.utils.FileStorageUtils; @@@ -60,11 -55,14 +58,14 @@@ public class PreviewImagePagerAdapter e /** * Constructor. * - * @param fragmentManager {@link FragmentManager} instance that will handle the {@link Fragment}s provided by the adapter. + * @param fragmentManager {@link FragmentManager} instance that will handle + * the {@link Fragment}s provided by the adapter. * @param parentFolder Folder where images will be searched for. * @param storageManager Bridge to database. */ - public PreviewImagePagerAdapter(FragmentManager fragmentManager, OCFile parentFolder, Account account, FileDataStorageManager storageManager) { + public PreviewImagePagerAdapter(FragmentManager fragmentManager, OCFile parentFolder, + Account account, FileDataStorageManager storageManager /*, + boolean onlyOnDevice*/) { super(fragmentManager); if (fragmentManager == null) { @@@ -79,7 -77,8 +80,8 @@@ mAccount = account; mStorageManager = storageManager; - mImageFiles = mStorageManager.getFolderImages(parentFolder); + // TODO Enable when "On Device" is recovered ? + mImageFiles = mStorageManager.getFolderImages(parentFolder/*, false*/); mImageFiles = FileStorageUtils.sortFolder(mImageFiles); @@@ -104,13 -103,18 +106,16 @@@ OCFile file = mImageFiles.get(i); Fragment fragment = null; if (file.isDown()) { - fragment = new PreviewImageFragment(file, mAccount, mObsoletePositions.contains(Integer.valueOf(i)), false); + fragment = PreviewImageFragment.newInstance(file, - mObsoletePositions.contains(Integer.valueOf(i))); ++ mObsoletePositions.contains(Integer.valueOf(i)), false); + } else if (mDownloadErrors.contains(Integer.valueOf(i))) { - fragment = new FileDownloadFragment(file, mAccount, true); + fragment = FileDownloadFragment.newInstance(file, mAccount, true); ((FileDownloadFragment)fragment).setError(true); mDownloadErrors.remove(Integer.valueOf(i)); - } else { - fragment = new PreviewImageFragment(file, mAccount, mObsoletePositions.contains(Integer.valueOf(i)), true); - fragment = FileDownloadFragment.newInstance( - file, mAccount, mObsoletePositions.contains(Integer.valueOf(i)) - ); ++ fragment = PreviewImageFragment.newInstance(file, ++ mObsoletePositions.contains(Integer.valueOf(i)), true); } mObsoletePositions.remove(Integer.valueOf(i)); return fragment;