From: tobiasKaminsky Date: Thu, 29 Oct 2015 17:09:14 +0000 (+0100) Subject: Merge remote-tracking branch 'remotes/upstream/material_fab' into beta X-Git-Tag: beta-20151122~92 X-Git-Url: http://git.linex4red.de/pub/Android/ownCloud.git/commitdiff_plain/563e6cbdad4dc183f95e18fb254e4a97efbb9a26?hp=477c7a6b0a7c6b8300db4e3bedd890eaba718124 Merge remote-tracking branch 'remotes/upstream/material_fab' into beta --- diff --git a/.gitignore b/.gitignore index 8346dbfc..9b1a0d0c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ # built application files -*.apk *.ap_ # files for the dex VM @@ -39,4 +38,4 @@ tests/proguard-project.txt build # Actionbarsherlock is now ignored since scripts takes care of init the sub-modules. -actionbarsherlock \ No newline at end of file +actionbarsherlock diff --git a/AndroidManifest.xml b/AndroidManifest.xml index acb5f1d8..dacb8b89 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -110,12 +110,17 @@ + + + + + + + diff --git a/CHANGELOG.md b/CHANGELOG.md index 099a4456..10d22447 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,60 +1,9 @@ -## 1.8.0 (September 2015) -- New MATERIAL DESIGN theme -- Updated FILE TYPE ICONS -- Preview TXT files within the app -- COPY files & folders -- Preview the full file/folder name from the long press menu -- Set a file as FAVORITE (kept-in-sync) from the CONTEXT MENU -- Updated CONFLICT RESOLUTION dialog (wording) -- Updated background for images with TRANSPARENCY in GALLERY -- Hidden files will not enforce list view instead of GRID VIEW (folders from Picasa & others) -- Security: - + Updated network stack with security fixes (Jackrabbit 2.10.1) -- Bugs fixed: - + Fixed crash when ETag is lost - + Passcode creation not restarted on device rotation - + Recovered share icon shown on folders 'shared with me' - + User name added to subject when sending a share link through e-mail (fixed on SAMLed apps) - -## 1.7.2 (July 2015) -- New navigation drawer -- Improved Passcode -- Automatic grid view just for folders full of images -- More characters allowed in file names -- Support for servers in same domain, different path -- Bugs fixed: - + Frequent crashes in folder with several images - + Sync error in servers with huge quota and external storage enable - + Share by link error - + Some other crashes and minor bugs - -## 1.7.1 (April 2015) - -- Share link even with password enforced by server -- Get the app ready for oc 8.1 servers -- Added option to create new folder in uploads from external apps -- Improved management of deleted users -- Bugs fixed - + Fixed crash on Android 2.x devices - + Improvements on uploads - -## 1.7.0 (February 2015) - -- Download full folders -- Grid view for images -- Remote thumbnails (OC Server 8.0+) -- Added number of files and folders at the end of the list -- "Open with" in contextual menu -- Downloads added to Media Provider -- Uploads: - + Local thumbnails in section "Files" - + Multiple selection in "Content from other apps" (Android 4.3+) -- Gallery: - + proper handling of EXIF - + obey sorting in the list of files -- Settings view updated -- Improved subjects in e-mails -- Bugs fixed - +# 2015-10-29 +- PR [#1099](https://github.com/owncloud/android/pull/1099) "Switch list vs grid" merged +# 2015-10-26 +- start of branch +- PR [#745](https://github.com/owncloud/android/pull/745) merged +- PR [#1044](https://github.com/owncloud/android/pull/1044) merged: < 8.1: GalleryPlus app needed, >= 8.2 Gallery app needed +- PR [#1111](https://github.com/owncloud/android/pull/1111) merged \ No newline at end of file diff --git a/README.md b/README.md index e3ff5353..d8808f1b 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,17 @@ -#This is the Android client for [ownCloud][0] +#This is the BETA Android client for [ownCloud][0] + +The BETA app is only intended to be used by experienced users that want to use and test the latest features. +All pull requests labeled "3 - to review" or higher will be included into the branch. +If you find a bug please comment in the corresponding pull request or create a new issue with the label "Beta". + +The compiled APKs can be found [here][2] + +The changelog is found [here][3] The app performs file synchronization with an ownCloud server. Other ownCloud features may be added in the future, but they are not a priority right now. ## Build Status on -Git master: ![Build Status](https://api.travis-ci.org/owncloud/android.svg?branch=master) - -Git stable: ![Build Status](https://api.travis-ci.org/owncloud/android.svg?branch=stable) +Git beta: ![Build Status](https://api.travis-ci.org/owncloud/android.svg?branch=beta) ## Development @@ -14,6 +20,8 @@ Make sure you read [SETUP.md][1] when you start working on this project. [0]: https://github.com/owncloud/core [1]: https://github.com/owncloud/android/blob/master/SETUP.md +[2]: https://github.com/owncloud/android/tree/beta/apks/ +[3]: https://github.com/owncloud/android/blob/beta/CHANGELOG.md ### Contributing Please see [Contribution Guidelines](https://owncloud.org/contribute/). Fork this repository and contribute back using diff --git a/android-release.apk b/android-release.apk new file mode 100644 index 00000000..61a3b3bc Binary files /dev/null and b/android-release.apk differ diff --git a/apks/owncloud-beta-2015-10-26.apk b/apks/owncloud-beta-2015-10-26.apk new file mode 100644 index 00000000..61a3b3bc Binary files /dev/null and b/apks/owncloud-beta-2015-10-26.apk differ diff --git a/build.gradle b/build.gradle index 817b5281..be674c9f 100644 --- a/build.gradle +++ b/build.gradle @@ -30,6 +30,11 @@ dependencies { android { compileSdkVersion 22 buildToolsVersion "22.0.1" + + defaultConfig { + applicationId "com.owncloud.android.beta" + } + sourceSets { main { manifest.srcFile 'AndroidManifest.xml' diff --git a/owncloud-android-library b/owncloud-android-library index ecc3415e..652cd28b 160000 --- a/owncloud-android-library +++ b/owncloud-android-library @@ -1 +1 @@ -Subproject commit ecc3415e3e3c13fa8f73fdd51a88c1ab7087b199 +Subproject commit 652cd28bb15672eaedfe8c1d9a46cf293c909b89 diff --git a/res/drawable-hdpi/ic_view_list.png b/res/drawable-hdpi/ic_view_list.png new file mode 100644 index 00000000..64ad8e14 Binary files /dev/null and b/res/drawable-hdpi/ic_view_list.png differ diff --git a/res/drawable-hdpi/ic_view_module.png b/res/drawable-hdpi/ic_view_module.png new file mode 100644 index 00000000..7982e383 Binary files /dev/null and b/res/drawable-hdpi/ic_view_module.png differ diff --git a/res/drawable-mdpi/ic_view_list.png b/res/drawable-mdpi/ic_view_list.png new file mode 100644 index 00000000..4aca55c6 Binary files /dev/null and b/res/drawable-mdpi/ic_view_list.png differ diff --git a/res/drawable-mdpi/ic_view_module.png b/res/drawable-mdpi/ic_view_module.png new file mode 100644 index 00000000..f308a32b Binary files /dev/null and b/res/drawable-mdpi/ic_view_module.png differ diff --git a/res/drawable-xhdpi/ic_view_list.png b/res/drawable-xhdpi/ic_view_list.png new file mode 100644 index 00000000..b81d9102 Binary files /dev/null and b/res/drawable-xhdpi/ic_view_list.png differ diff --git a/res/drawable-xhdpi/ic_view_module.png b/res/drawable-xhdpi/ic_view_module.png new file mode 100644 index 00000000..b3548535 Binary files /dev/null and b/res/drawable-xhdpi/ic_view_module.png differ diff --git a/res/menu/file_actions_menu.xml b/res/menu/file_actions_menu.xml index 3e6f4cd4..4a295d53 100644 --- a/res/menu/file_actions_menu.xml +++ b/res/menu/file_actions_menu.xml @@ -1,4 +1,5 @@ - + Visas datnes + Iestatījumi + Aizvērt Atvērt Vispārīgi Vairāk @@ -40,6 +43,8 @@ Palīdzība Ieteikt draugam Atsauksmes + Izmēģini %1$s uz savu viedtālruni! + Pārbaudīt serveri Lietotājvārds Parole Datnes @@ -56,6 +61,7 @@ Augšupielādē sekundes atpakaļ Te vēl nekas nav. Rīkojies, sāc augšupielādēt! + Ielādē… Šajā mapē nav failu Uzsitiet uz datnes, lai redzētu papildinformāciju. Izmērs: @@ -65,6 +71,8 @@ Lejupielādēt Atsvaidzināt failu Datne tika pārsaukta uz %1$s augšupielādes laikā + Dalīt saiti + Pārtraukt dalīt saiti Jā Nē Labi @@ -119,6 +127,7 @@ Izņemt Tikai lokālos Tikai lokālos + No servera Veiksmīgi izņemts Neizdevās izņemt Ievadīt jaunu nosaukumu @@ -126,6 +135,7 @@ Nevarēja pabeigt pārsaukšanu Nevarēja atzīmēt attālinātas datnes Datnes saturs jau ir sinhronizēts + Mapi nevarēja izveidot Uzgaidīt brīdi Negaidīta problēma; lūdzu, izvēlieties datni no citas lietotnes Netika izvēlēta neviena datne @@ -151,14 +161,35 @@ Kam: Paraksts: Algoritms: + PNG attēls Attēlus augšupielādēt tikai caur WiFi /TūlītējaAugšupielāde Paturēt abas + Šo attēlu nevar attēlot + Ievadiet paroli + Jums ir jāievada paroli Sūtīt + Kopēt saiti + lai pārsauktu šo datni + lai dzēstu šo datni + lai dalītu šo datni + lai pārtrauktu šis datnes dalīšanu + lai izveidotu datni Konti + Pievienot kontu + Ielādē datus… Nepareiza parole + Pārvietot + Šeit nekā nav. Jūs varat pievienot mapi! Izvēlieties + lai pārvietotu šo datni + lai kopētu šo datni Drošība + koplietots + ar jums Servera adrese + Lietotājvārds + 1 mape + 1 datne diff --git a/res/values-tzl/strings.xml b/res/values-tzl/strings.xml deleted file mode 100644 index 37e61524..00000000 --- a/res/values-tzl/strings.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - diff --git a/res/values/setup.xml b/res/values/setup.xml index 76bdd9f8..5c775e92 100644 --- a/res/values/setup.xml +++ b/res/values/setup.xml @@ -1,12 +1,12 @@ - ownCloud + Owncloud Beta owncloud org.owncloud - owncloud.db + owncloud-beta.db ownCloud - owncloud + owncloud-beta Owncloud_ ownCloud Mozilla/5.0 (Android) ownCloud-android/%1$s diff --git a/res/values/strings.xml b/res/values/strings.xml index 267d713e..43cb0d96 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -263,9 +263,11 @@ 389 KB 2012/05/18 12:23 PM 12:23:45 - - Upload pictures via WiFi only - Upload videos via WiFi only + + Upload pictures via wifi only + Upload when charging only + Upload videos via wifi only + Upload when charging only /InstantUpload File conflict Which files do you want to keep? If you select both versions, the local file will have a number added to its name. @@ -277,7 +279,7 @@ This image cannot be shown %1$s could not be copied to %2$s local folder - Upload Path + Upload path Sorry, sharing is not enabled on your server. Please contact your administrator. @@ -342,7 +344,7 @@ Instant Uploads Security - Upload Video Path + Upload video path Download of %1$s folder could not be completed shared @@ -365,5 +367,6 @@ %1$d files %1$d files, 1 folder %1$d files, %2$d folders - + Switch to grid view + Switch to list view diff --git a/res/xml/preferences.xml b/res/xml/preferences.xml index 4823a83f..5c853fe4 100644 --- a/res/xml/preferences.xml +++ b/res/xml/preferences.xml @@ -3,7 +3,7 @@ ownCloud Android client application Copyright (C) 2012 Bartek Przybylski - Copyright (C) 2015 ownCloud Inc. + Copyright (C) 2012-2013 ownCloud Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 2, @@ -18,52 +18,82 @@ along with this program. If not, see . --> - + - + + - - - + + + + - + android:dependency="instant_uploading" + android:disableDependentsState="true" + android:title="@string/instant_upload_on_wifi" + android:key="instant_upload_on_wifi"/> + + + + android:dependency="instant_video_uploading" + android:disableDependentsState="true" + android:title="@string/prefs_instant_video_upload_path_title" + android:key="instant_video_upload_path" /> - - - - - - - - - - - + + + + + + - + diff --git a/src/com/owncloud/android/datamodel/OCFile.java b/src/com/owncloud/android/datamodel/OCFile.java index 4baf1ea5..0c7cc714 100644 --- a/src/com/owncloud/android/datamodel/OCFile.java +++ b/src/com/owncloud/android/datamodel/OCFile.java @@ -27,6 +27,7 @@ import android.webkit.MimeTypeMap; import com.owncloud.android.lib.common.utils.Log_OC; import java.io.File; +import java.util.Enumeration; import third_parties.daveKoeller.AlphanumComparator; public class OCFile implements Parcelable, Comparable { @@ -74,6 +75,8 @@ public class OCFile implements Parcelable, Comparable { private boolean mIsDownloading; + private boolean mShowGridView; + /** * Create new {@link OCFile} with given path. diff --git a/src/com/owncloud/android/datamodel/ThumbnailsCacheManager.java b/src/com/owncloud/android/datamodel/ThumbnailsCacheManager.java index f0ecf767..e8496951 100644 --- a/src/com/owncloud/android/datamodel/ThumbnailsCacheManager.java +++ b/src/com/owncloud/android/datamodel/ThumbnailsCacheManager.java @@ -29,18 +29,25 @@ 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.Canvas; +import android.graphics.Point; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.ColorDrawable; 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; @@ -142,11 +149,12 @@ public class ThumbnailsCacheManager { 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 @@ -157,6 +165,12 @@ public class ThumbnailsCacheManager { 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); @@ -175,12 +189,15 @@ public class ThumbnailsCacheManager { } 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){ @@ -206,7 +223,14 @@ public class ThumbnailsCacheManager { 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); } } } @@ -217,12 +241,13 @@ public class ThumbnailsCacheManager { * @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); @@ -243,31 +268,56 @@ public class ThumbnailsCacheManager { 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 temp = BitmapUtils.decodeSampledBitmapFromFile( - file.getStoragePath(), px, px); - Bitmap bitmap = ThumbnailUtils.extractThumbnail(temp, px, px); + Bitmap tempBitmap = BitmapUtils.decodeSampledBitmapFromFile( + file.getStoragePath(), pxW, pxH); + Bitmap bitmap = ThumbnailUtils.extractThumbnail(tempBitmap, 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); @@ -279,27 +329,51 @@ public class ThumbnailsCacheManager { if (mClient != null && serverOCVersion != null) { if (serverOCVersion.supportsRemoteThumbnails()) { try { - String uri = mClient.getBaseUri() + "" + - "/index.php/apps/files/api/v1/thumbnail/" + - px + "/" + px + Uri.encode(file.getRemotePath(), "/"); - Log_OC.d("Thumbnail", "URI: " + uri); - GetMethod get = new GetMethod(uri); - int status = mClient.executeMethod(get); - if (status == HttpStatus.SC_OK) { - InputStream inputStream = get.getResponseBodyAsStream(); - Bitmap bitmap = BitmapFactory.decodeStream(inputStream); - thumbnail = ThumbnailUtils.extractThumbnail(bitmap, px, px); - - // Handle PNG - if (file.getMimetype().equalsIgnoreCase("image/png")) { - thumbnail = handlePNG(thumbnail, px); + if (mIsThumbnail) { + String uri = mClient.getBaseUri() + "" + + "/index.php/apps/files/api/v1/thumbnail/" + + pxW + "/" + pxH + Uri.encode(file.getRemotePath(), "/"); + Log_OC.d("Thumbnail", "Download URI: " + uri); + GetMethod get = new GetMethod(uri); + int status = mClient.executeMethod(get); + if (status == HttpStatus.SC_OK) { + InputStream inputStream = get.getResponseBodyAsStream(); + Bitmap bitmap = BitmapFactory.decodeStream(inputStream); + thumbnail = ThumbnailUtils.extractThumbnail(bitmap, pxW, pxH); + } else { + Log_OC.d(TAG, "Status: " + status); + } + } else { + String gallery = ""; + if (serverOCVersion.supportsNativeGallery()){ + gallery = "gallery"; + } else { + gallery = "galleryplus"; } - // Add thumbnail to cache - if (thumbnail != null) { - addBitmapToCache(imageKey, thumbnail); + String uri = mClient.getBaseUri() + + "/index.php/apps/" + gallery + "/api/preview/" + Integer.parseInt(file.getRemoteId().substring(0,8)) + + "/" + pxW + "/" + pxH; + Log_OC.d("Thumbnail", "FileName: " + file.getFileName() + " Download URI: " + uri); + GetMethod get = new GetMethod(uri); + int status = mClient.executeMethod(get); + if (status == HttpStatus.SC_OK) { + InputStream inputStream = get.getResponseBodyAsStream(); + Bitmap bitmap = BitmapFactory.decodeStream(inputStream); + // Download via gallery app + thumbnail = bitmap; } } + + // Handle PNG + if (thumbnail != null && file.getMimetype().equalsIgnoreCase("image/png")) { + thumbnail = handlePNG(thumbnail, pxW); + } + + // Add thumbnail to cache + if (thumbnail != null) { + addBitmapToCache(imageKey, thumbnail); + } } catch (Exception e) { e.printStackTrace(); } @@ -327,24 +401,32 @@ public class ThumbnailsCacheManager { return resultBitmap; } - 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 --git a/src/com/owncloud/android/files/FileMenuFilter.java b/src/com/owncloud/android/files/FileMenuFilter.java index f7fee626..1d5ca454 100644 --- a/src/com/owncloud/android/files/FileMenuFilter.java +++ b/src/com/owncloud/android/files/FileMenuFilter.java @@ -229,7 +229,6 @@ public class FileMenuFilter { } else { toShow.add(R.id.action_unfavorite_file); } - } } diff --git a/src/com/owncloud/android/files/FileOperationsHelper.java b/src/com/owncloud/android/files/FileOperationsHelper.java index fba62091..88cc8843 100644 --- a/src/com/owncloud/android/files/FileOperationsHelper.java +++ b/src/com/owncloud/android/files/FileOperationsHelper.java @@ -27,14 +27,17 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; +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.network.WebdavUtils; @@ -43,12 +46,19 @@ import com.owncloud.android.lib.resources.status.OwnCloudVersion; import com.owncloud.android.services.OperationsService; import com.owncloud.android.services.observer.FileObserverService; import com.owncloud.android.ui.activity.FileActivity; +import com.owncloud.android.ui.adapter.DiskLruImageCacheFileProvider; import com.owncloud.android.ui.dialog.ShareLinkToDialog; import org.apache.http.protocol.HTTP; import java.util.List; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; + /** * */ @@ -236,6 +246,24 @@ public class FileOperationsHelper { } } + 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) { diff --git a/src/com/owncloud/android/files/InstantUploadBroadcastReceiver.java b/src/com/owncloud/android/files/InstantUploadBroadcastReceiver.java index 47f7127b..33ad1cc1 100644 --- a/src/com/owncloud/android/files/InstantUploadBroadcastReceiver.java +++ b/src/com/owncloud/android/files/InstantUploadBroadcastReceiver.java @@ -29,14 +29,15 @@ import com.owncloud.android.files.services.FileUploader; import com.owncloud.android.lib.common.utils.Log_OC; import com.owncloud.android.utils.FileStorageUtils; - import android.accounts.Account; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.database.Cursor; import android.net.ConnectivityManager; import android.net.NetworkInfo.State; +import android.os.BatteryManager; import android.preference.PreferenceManager; import android.provider.MediaStore.Images; import android.provider.MediaStore.Video; @@ -58,7 +59,7 @@ public class InstantUploadBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Log_OC.d(TAG, "Received: " + intent.getAction()); - if (intent.getAction().equals(android.net.ConnectivityManager.CONNECTIVITY_ACTION)) { + if (intent.getAction().equals(android.net.ConnectivityManager.CONNECTIVITY_ACTION) || intent.getAction().equals(Intent.ACTION_POWER_CONNECTED)) { handleConnectivityAction(context, intent); }else if (intent.getAction().equals(NEW_PHOTO_ACTION_UNOFFICIAL)) { handleNewPictureAction(context, intent); @@ -103,7 +104,6 @@ public class InstantUploadBroadcastReceiver extends BroadcastReceiver { file_name = c.getString(c.getColumnIndex(Images.Media.DISPLAY_NAME)); mime_type = c.getString(c.getColumnIndex(Images.Media.MIME_TYPE)); c.close(); - Log_OC.d(TAG, file_path + ""); // save always temporally the picture to upload @@ -111,7 +111,10 @@ public class InstantUploadBroadcastReceiver extends BroadcastReceiver { db.putFileForLater(file_path, account.name, null); db.close(); - if (!isOnline(context) || (instantPictureUploadViaWiFiOnly(context) && !isConnectedViaWiFi(context))) { + if (!isOnline(context) + || (instantPictureUploadViaWiFiOnly(context) && !isConnectedViaWiFi(context)) + || (instantUploadWhenChargingOnly(context) && !isCharging(context)) + ) { return; } @@ -155,8 +158,16 @@ public class InstantUploadBroadcastReceiver extends BroadcastReceiver { mime_type = c.getString(c.getColumnIndex(Video.Media.MIME_TYPE)); c.close(); Log_OC.d(TAG, file_path + ""); + + // save always temporally the picture to upload + DbHandler db = new DbHandler(context); + db.putFileForLater(file_path, account.name, null); + db.close(); - if (!isOnline(context) || (instantVideoUploadViaWiFiOnly(context) && !isConnectedViaWiFi(context))) { + if (!isOnline(context) + || (instantVideoUploadViaWiFiOnly(context) && !isConnectedViaWiFi(context)) + || (instantVideoUploadWhenChargingOnly(context) && !isCharging(context)) + ) { return; } @@ -172,14 +183,18 @@ public class InstantUploadBroadcastReceiver extends BroadcastReceiver { } private void handleConnectivityAction(Context context, Intent intent) { - if (!instantPictureUploadEnabled(context)) { + if (!instantPictureUploadEnabled(context) && !instantVideoUploadEnabled(context)) { Log_OC.d(TAG, "Instant upload disabled, don't upload anything"); return; } if (!intent.hasExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY) && isOnline(context) - && (!instantPictureUploadViaWiFiOnly(context) || (instantPictureUploadViaWiFiOnly(context) == isConnectedViaWiFi(context) == true))) { + && (!instantUploadWhenChargingOnly(context) || (instantUploadWhenChargingOnly(context) && isCharging(context))) + && (!instantVideoUploadWhenChargingOnly(context) || (instantVideoUploadWhenChargingOnly(context) && isCharging(context))) + && (!instantPictureUploadViaWiFiOnly(context) || (instantPictureUploadViaWiFiOnly(context) && isConnectedViaWiFi(context))) + && (!instantVideoUploadViaWiFiOnly(context) || (instantVideoUploadViaWiFiOnly(context) && isConnectedViaWiFi(context))) + ) { DbHandler db = new DbHandler(context); Cursor c = db.getAwaitingFiles(); if (c.moveToFirst()) { @@ -217,7 +232,6 @@ public class InstantUploadBroadcastReceiver extends BroadcastReceiver { c.close(); db.close(); } - } public static boolean isOnline(Context context) { @@ -231,6 +245,18 @@ public class InstantUploadBroadcastReceiver extends BroadcastReceiver { && cm.getActiveNetworkInfo().getType() == ConnectivityManager.TYPE_WIFI && cm.getActiveNetworkInfo().getState() == State.CONNECTED; } + + public static boolean isCharging(Context context){ + IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); + Intent batteryStatus = context.registerReceiver(null, ifilter); + + int status = 0; + if (batteryStatus != null) { + status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1); + } + return status == BatteryManager.BATTERY_STATUS_CHARGING || + status == BatteryManager.BATTERY_STATUS_FULL; + } public static boolean instantPictureUploadEnabled(Context context) { return PreferenceManager.getDefaultSharedPreferences(context).getBoolean("instant_uploading", false); @@ -247,4 +273,10 @@ public class InstantUploadBroadcastReceiver extends BroadcastReceiver { public static boolean instantVideoUploadViaWiFiOnly(Context context) { return PreferenceManager.getDefaultSharedPreferences(context).getBoolean("instant_video_upload_on_wifi", false); } + public static boolean instantUploadWhenChargingOnly(Context context) { + return PreferenceManager.getDefaultSharedPreferences(context).getBoolean("instant_upload_on_charging", false); + } + public static boolean instantVideoUploadWhenChargingOnly(Context context) { + return PreferenceManager.getDefaultSharedPreferences(context).getBoolean("instant_video_upload_on_charging", false); + } } diff --git a/src/com/owncloud/android/ui/activity/FileDisplayActivity.java b/src/com/owncloud/android/ui/activity/FileDisplayActivity.java index aa3c1ef3..7b97a9c8 100644 --- a/src/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/src/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -154,8 +154,9 @@ public class FileDisplayActivity extends HookActivity private static String DIALOG_CERT_NOT_SAVED = "DIALOG_CERT_NOT_SAVED"; private OCFile mWaitingToSend; + private Menu mOptionsMenu; + - @Override protected void onCreate(Bundle savedInstanceState) { Log_OC.v(TAG, "onCreate() start"); @@ -316,6 +317,12 @@ public class FileDisplayActivity extends HookActivity startTextPreview(file); } + if (DisplayUtils.isGridView(getFile(), getStorageManager())){ + switchToGridView(); + } else { + switchToListView(); + } + } else { Log_OC.wtf(TAG, "initFragments() called with invalid NULLs!"); if (getAccount() == null) { @@ -482,6 +489,7 @@ public class FileDisplayActivity extends HookActivity boolean drawerOpen = mDrawerLayout.isDrawerOpen(GravityCompat.START); menu.findItem(R.id.action_sort).setVisible(!drawerOpen); menu.findItem(R.id.action_sync_account).setVisible(!drawerOpen); + menu.findItem(R.id.action_switch_view).setVisible(!drawerOpen); return super.onPrepareOptionsMenu(menu); } @@ -491,6 +499,12 @@ public class FileDisplayActivity extends HookActivity MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.main_menu, menu); menu.findItem(R.id.action_create_dir).setVisible(false); + mOptionsMenu = menu; + + MenuItem menuItem = mOptionsMenu.findItem(R.id.action_switch_view); + + changeGridIcon(); + return true; } @@ -545,6 +559,23 @@ public class FileDisplayActivity extends HookActivity builder.create().show(); break; } + case R.id.action_switch_view:{ + if (isGridView()){ + item.setTitle(getApplicationContext().getString(R.string.action_switch_grid_view)); + item.setIcon(ContextCompat.getDrawable(getApplicationContext(), + R.drawable.ic_view_module)); + DisplayUtils.setViewMode(getFile(), false); + switchToListView(); + } else { + item.setTitle(getApplicationContext().getString(R.string.action_switch_list_view)); + item.setIcon(ContextCompat.getDrawable(getApplicationContext(), + R.drawable.ic_view_list)); + DisplayUtils.setViewMode(getFile(), true); + switchToGridView(); + } + + return true; + } default: retval = super.onOptionsItemSelected(item); } @@ -826,6 +857,20 @@ public class FileDisplayActivity extends HookActivity setFile(listOfFiles.getCurrentFile()); } cleanSecondFragment(); + changeGridIcon(); + } + } + + private void changeGridIcon(){ + MenuItem menuItem = mOptionsMenu.findItem(R.id.action_switch_view); + if (DisplayUtils.isGridView(getFile(), getStorageManager())){ + menuItem.setTitle(getApplicationContext().getString(R.string.action_switch_list_view)); + menuItem.setIcon(ContextCompat.getDrawable(getApplicationContext(), + R.drawable.ic_view_list)); + } else { + menuItem.setTitle(getApplicationContext().getString(R.string.action_switch_grid_view)); + menuItem.setIcon(ContextCompat.getDrawable(getApplicationContext(), + R.drawable.ic_view_module)); } } @@ -1234,6 +1279,15 @@ public class FileDisplayActivity extends HookActivity cleanSecondFragment(); // Sync Folder startSyncFolderOperation(directory, false); + + MenuItem menuItem = mOptionsMenu.findItem(R.id.action_switch_view); + + changeGridIcon(); + if (DisplayUtils.isGridView(directory, getStorageManager())){ + switchToGridView(); + } else { + switchToListView(); + } } /** @@ -1831,6 +1885,13 @@ public class FileDisplayActivity extends HookActivity private void sortByName(boolean ascending) { getListOfFilesFragment().sortByName(ascending); } + private boolean isGridView(){ return getListOfFilesFragment().isGridView(); } + private void switchToGridView() { + getListOfFilesFragment().switchToGridView(); + } + private void switchToListView() { + getListOfFilesFragment().switchToListView(); + } public void allFilesOption() { browseToRoot(); diff --git a/src/com/owncloud/android/ui/activity/Preferences.java b/src/com/owncloud/android/ui/activity/Preferences.java index e1c5c10d..d980b977 100644 --- a/src/com/owncloud/android/ui/activity/Preferences.java +++ b/src/com/owncloud/android/ui/activity/Preferences.java @@ -457,8 +457,8 @@ public class Preferences extends PreferenceActivity mPrefInstantUploadCategory.addPreference(mPrefInstantUploadPathWiFi); mPrefInstantUploadCategory.addPreference(mPrefInstantUploadPath); } else { - mPrefInstantUploadCategory.removePreference(mPrefInstantUploadPathWiFi); - mPrefInstantUploadCategory.removePreference(mPrefInstantUploadPath); +// mPrefInstantUploadCategory.removePreference(mPrefInstantUploadPathWiFi); +// mPrefInstantUploadCategory.removePreference(mPrefInstantUploadPath); } } @@ -467,8 +467,8 @@ public class Preferences extends PreferenceActivity mPrefInstantUploadCategory.addPreference(mPrefInstantVideoUploadPathWiFi); mPrefInstantUploadCategory.addPreference(mPrefInstantVideoUploadPath); } else { - mPrefInstantUploadCategory.removePreference(mPrefInstantVideoUploadPathWiFi); - mPrefInstantUploadCategory.removePreference(mPrefInstantVideoUploadPath); +// mPrefInstantUploadCategory.removePreference(mPrefInstantVideoUploadPathWiFi); +// mPrefInstantUploadCategory.removePreference(mPrefInstantVideoUploadPath); } } @@ -805,7 +805,7 @@ public class Preferences extends PreferenceActivity SharedPreferences appPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); mUploadVideoPath = appPrefs.getString("instant_video_upload_path", getString(R.string.instant_upload_path)); - mPrefInstantVideoUploadPath.setSummary(mUploadVideoPath); +// mPrefInstantVideoUploadPath.setSummary(mUploadVideoPath); } /** diff --git a/src/com/owncloud/android/ui/adapter/DiskLruImageCache.java b/src/com/owncloud/android/ui/adapter/DiskLruImageCache.java index 0f2536f5..ab80aef2 100644 --- a/src/com/owncloud/android/ui/adapter/DiskLruImageCache.java +++ b/src/com/owncloud/android/ui/adapter/DiskLruImageCache.java @@ -120,10 +120,10 @@ public class DiskLruImageCache { } final InputStream in = snapshot.getInputStream( 0 ); if ( in != null ) { - final BufferedInputStream buffIn = + final BufferedInputStream buffIn = new BufferedInputStream( in, IO_BUFFER_SIZE ); - bitmap = BitmapFactory.decodeStream( buffIn ); - } + bitmap = BitmapFactory.decodeStream( buffIn ); + } } catch ( IOException e ) { e.printStackTrace(); } finally { diff --git a/src/com/owncloud/android/ui/adapter/DiskLruImageCacheFileProvider.java b/src/com/owncloud/android/ui/adapter/DiskLruImageCacheFileProvider.java new file mode 100644 index 00000000..fe3f6ea2 --- /dev/null +++ b/src/com/owncloud/android/ui/adapter/DiskLruImageCacheFileProvider.java @@ -0,0 +1,121 @@ +/** + * ownCloud Android client application + * + * Copyright (C) 2015 Tobias Kaminsky + * Copyright (C) 2015 ownCloud Inc. + * + * This program is free software: you can redistribute it and/or modify + * 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, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * adapted from: http://stephendnicholas.com/archives/974 + * + */ + +package com.owncloud.android.ui.adapter; + +import android.accounts.Account; +import android.content.ContentProvider; +import android.content.ContentValues; +import android.content.UriMatcher; +import android.database.Cursor; +import android.graphics.Bitmap; +import android.net.Uri; +import android.os.ParcelFileDescriptor; + +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; +import java.io.IOException; + +public class DiskLruImageCacheFileProvider extends ContentProvider { + private static String TAG = FileDataStorageManager.class.getSimpleName(); + + public static final String AUTHORITY = "com.owncloud.imageCache.provider"; + + @Override + public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { + Account account = AccountUtils.getCurrentOwnCloudAccount(MainApp.getAppContext()); + FileDataStorageManager fileDataStorageManager = new FileDataStorageManager(account, + MainApp.getAppContext().getContentResolver()); + + OCFile ocFile = fileDataStorageManager.getFileByPath(uri.getPath()); + + Bitmap thumbnail = ThumbnailsCacheManager.getBitmapFromDiskCache( + String.valueOf("r" + ocFile.getRemoteId())); + + // 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 (IOException e) { + e.printStackTrace(); + } + + return ParcelFileDescriptor.open(f, ParcelFileDescriptor.MODE_READ_ONLY); + } + + + @Override + public boolean onCreate() { + return true; + } + + @Override + public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { + return null; + } + + @Override + public String getType(Uri uri) { + return null; + } + + @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; + } +} diff --git a/src/com/owncloud/android/ui/adapter/FileListListAdapter.java b/src/com/owncloud/android/ui/adapter/FileListListAdapter.java index 51883670..410eeeda 100644 --- a/src/com/owncloud/android/ui/adapter/FileListListAdapter.java +++ b/src/com/owncloud/android/ui/adapter/FileListListAdapter.java @@ -322,7 +322,7 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter { task ); fileIcon.setImageDrawable(asyncDrawable); - task.execute(file); + task.execute(file, true); } } @@ -490,4 +490,8 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter { public void setGridMode(boolean gridMode) { mGridMode = gridMode; } + + public boolean isGridMode() { + return mGridMode; + } } diff --git a/src/com/owncloud/android/ui/fragment/ExtendedListFragment.java b/src/com/owncloud/android/ui/fragment/ExtendedListFragment.java index 900fde98..6d93ab33 100644 --- a/src/com/owncloud/android/ui/fragment/ExtendedListFragment.java +++ b/src/com/owncloud/android/ui/fragment/ExtendedListFragment.java @@ -122,7 +122,7 @@ public class ExtendedListFragment extends Fragment return fabMain; } - protected void switchToGridView() { + public void switchToGridView() { if ((mCurrentListView == mListView)) { mListView.setAdapter(null); @@ -137,8 +137,8 @@ public class ExtendedListFragment extends Fragment mCurrentListView = mGridView; } } - - protected void switchToListView() { + + public void switchToListView() { if (mCurrentListView == mGridView) { mGridView.setAdapter(null); mRefreshGridLayout.setVisibility(View.GONE); @@ -152,6 +152,13 @@ public class ExtendedListFragment extends Fragment mCurrentListView = mListView; } } + + public boolean isGridView(){ + if (mAdapter instanceof FileListListAdapter) { + return ((FileListListAdapter) mAdapter).isGridMode(); + } + return false; + } @Override diff --git a/src/com/owncloud/android/ui/fragment/OCFileListFragment.java b/src/com/owncloud/android/ui/fragment/OCFileListFragment.java index 613b5c86..5a40b29c 100644 --- a/src/com/owncloud/android/ui/fragment/OCFileListFragment.java +++ b/src/com/owncloud/android/ui/fragment/OCFileListFragment.java @@ -61,6 +61,7 @@ import com.owncloud.android.ui.dialog.RenameFileDialogFragment; import com.owncloud.android.ui.dialog.UploadSourceDialogFragment; import com.owncloud.android.ui.preview.PreviewImageFragment; import com.owncloud.android.ui.preview.PreviewMediaFragment; +import com.owncloud.android.utils.DisplayUtils; import com.owncloud.android.utils.FileStorageUtils; import com.owncloud.android.ui.preview.PreviewTextFragment; @@ -448,12 +449,8 @@ public class OCFileListFragment extends ExtendedListFragment implements FileActi } else { mContainerActivity.getFileOperationsHelper().openFile(file); } - - } else { - // automatic download, preview on finish - ((FileDisplayActivity) mContainerActivity).startDownloadForPreview(file); + } - } } else { @@ -498,6 +495,9 @@ public class OCFileListFragment extends ExtendedListFragment implements FileActi item.setEnabled(false); } } + +// String.format(mContext.getString(R.string.subject_token), +// getClient().getCredentials().getUsername(), file.getFileName())); } } @@ -688,7 +688,7 @@ public class OCFileListFragment extends ExtendedListFragment implements FileActi OwnCloudVersion version = AccountUtils.getServerVersion( ((FileActivity)mContainerActivity).getAccount()); if (version != null && version.supportsRemoteThumbnails() && - imagesCount > 0 && imagesCount == filesCount) { + DisplayUtils.isGridView(mFile, mContainerActivity.getStorageManager())) { switchToGridView(); registerLongClickListener(); } else { diff --git a/src/com/owncloud/android/ui/preview/ImageViewCustom.java b/src/com/owncloud/android/ui/preview/ImageViewCustom.java index 69182d6e..5bb24e7b 100644 --- a/src/com/owncloud/android/ui/preview/ImageViewCustom.java +++ b/src/com/owncloud/android/ui/preview/ImageViewCustom.java @@ -4,12 +4,16 @@ import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; +import android.graphics.Movie; import android.os.Build; import android.util.AttributeSet; import android.view.View; import android.widget.ImageView; -import com.owncloud.android.lib.common.utils.Log_OC; +import com.owncloud.android.datamodel.OCFile; + +import java.io.FileInputStream; +import java.io.InputStream; public class ImageViewCustom extends ImageView { @@ -23,7 +27,12 @@ public class ImageViewCustom extends ImageView { private int mBitmapHeight; private int mBitmapWidth; - + private Movie mGifMovie; + private int mMovieWidth, mMovieHeight; + private long mMovieDuration; + private long mMovieRunDuration; + private long mLastTick; + public ImageViewCustom(Context context) { super(context); } @@ -39,18 +48,58 @@ public class ImageViewCustom extends ImageView { @SuppressLint("NewApi") @Override protected void onDraw(Canvas canvas) { - if(IS_ICS_OR_HIGHER && checkIfMaximumBitmapExceed(canvas) || IS_VERSION_BUGGY_ON_RECYCLES ) { // Software type is set with two targets: // 1. prevent that bitmaps larger than maximum textures allowed are shown as black views in devices // with LAYER_TYPE_HARDWARE enabled by default; - // 2. grant that bitmaps are correctly dellocated from memory in versions suffering the bug fixed in + // 2. grant that bitmaps are correctly de-allocated from memory in versions suffering the bug fixed in // https://android.googlesource.com/platform/frameworks/base/+/034de6b1ec561797a2422314e6ef03e3cd3e08e0; // setLayerType(View.LAYER_TYPE_SOFTWARE, null); } - super.onDraw(canvas); + if(mGifMovie == null){ + super.onDraw(canvas); + } else { + long nowTick = android.os.SystemClock.uptimeMillis(); + if (mLastTick == 0) { + mMovieRunDuration = 0; + } else { + mMovieRunDuration += nowTick - mLastTick; + if(mMovieRunDuration > mMovieDuration){ + mMovieRunDuration = 0; + } + } + + mGifMovie.setTime((int) mMovieRunDuration); + + float scale; + if(mGifMovie.height() > getHeight() || mGifMovie.width() > getWidth()) { + scale = (1f / Math.min(canvas.getHeight() / mGifMovie.height(), + canvas.getWidth() / mGifMovie.width())) + 0.25f; + } else { + scale = Math.min(canvas.getHeight() / mGifMovie.height(), + canvas.getWidth() / mGifMovie.width()); + } + + canvas.scale(scale, scale); + canvas.translate(((float) getWidth() / scale - (float) mGifMovie.width()) / 2f, + ((float) getHeight() / scale - (float) mGifMovie.height()) /2f); + + mGifMovie.draw(canvas, 0, 0); + + mLastTick = nowTick; + invalidate(); + } + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + if (mGifMovie == null){ + setMeasuredDimension(widthMeasureSpec, heightMeasureSpec); + } else { + setMeasuredDimension(mMovieWidth, mMovieHeight); + } } /** @@ -60,13 +109,9 @@ public class ImageViewCustom extends ImageView { */ @SuppressLint("NewApi") private boolean checkIfMaximumBitmapExceed(Canvas canvas) { - Log_OC.v(TAG, "Canvas maximum: " + canvas.getMaximumBitmapWidth() + " - " + canvas.getMaximumBitmapHeight()); - if (mBitmapWidth > canvas.getMaximumBitmapWidth() - || mBitmapHeight > canvas.getMaximumBitmapHeight()) { - return true; - } - - return false; + return mBitmapWidth > canvas.getMaximumBitmapWidth() + || mBitmapHeight > canvas.getMaximumBitmapHeight(); + } @Override @@ -74,10 +119,25 @@ public class ImageViewCustom extends ImageView { * Keeps the size of the bitmap cached in member variables for faster access in {@link #onDraw(Canvas)} , * but without keeping another reference to the {@link Bitmap} */ - public void setImageBitmap (Bitmap bm) { + public void setImageBitmap(Bitmap bm) { mBitmapWidth = bm.getWidth(); mBitmapHeight = bm.getHeight(); super.setImageBitmap(bm); } + public void setGifImage(OCFile file){ + try { + InputStream gifInputStream = new FileInputStream(file.getStoragePath()); + setLayerType(View.LAYER_TYPE_SOFTWARE, null); + setFocusable(true); + + mGifMovie = Movie.decodeStream(gifInputStream); + mMovieWidth = mGifMovie.width(); + mMovieHeight = mGifMovie.height(); + mMovieDuration = mGifMovie.duration(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } diff --git a/src/com/owncloud/android/ui/preview/PreviewImageActivity.java b/src/com/owncloud/android/ui/preview/PreviewImageActivity.java index 5cbacfcf..4b622cbf 100644 --- a/src/com/owncloud/android/ui/preview/PreviewImageActivity.java +++ b/src/com/owncloud/android/ui/preview/PreviewImageActivity.java @@ -430,12 +430,7 @@ public class PreviewImageActivity extends FileActivity implements 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(); } diff --git a/src/com/owncloud/android/ui/preview/PreviewImageFragment.java b/src/com/owncloud/android/ui/preview/PreviewImageFragment.java index e61e3355..c45f76cf 100644 --- a/src/com/owncloud/android/ui/preview/PreviewImageFragment.java +++ b/src/com/owncloud/android/ui/preview/PreviewImageFragment.java @@ -41,8 +41,10 @@ import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.TextView; +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; @@ -74,6 +76,8 @@ public class PreviewImageFragment extends FileFragment { private TextView mMessageView; private ProgressBar mProgressWheel; + private Boolean mShowResizedImage = false; + public Bitmap mBitmap = null; private static final String TAG = PreviewImageFragment.class.getSimpleName(); @@ -97,8 +101,10 @@ public class PreviewImageFragment extends FileFragment { * {@link FragmentStatePagerAdapter} * ; TODO better solution */ - 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); @@ -179,9 +185,6 @@ public class PreviewImageFragment extends FileFragment { if (getFile() == null) { throw new IllegalStateException("Instanced with a NULL OCFile"); } - if (!getFile().isDown()) { - throw new IllegalStateException("There is no local file to preview"); - } } @@ -199,10 +202,43 @@ public class PreviewImageFragment extends FileFragment { public void onStart() { super.onStart(); if (getFile() != null) { - mLoadBitmapTask = new LoadBitmapTask(mImageView, mMessageView, mProgressWheel); - //mLoadBitmapTask.execute(new String[]{getFile().getStoragePath()}); -// mLoadBitmapTask.execute(getFile().getStoragePath()); - mLoadBitmapTask.execute(getFile()); + 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.setVisibility(View.VISIBLE); + mBitmap = thumbnail; + } else { + // generate new Thumbnail + if (ThumbnailsCacheManager.cancelPotentialWork(getFile(), mImageView)) { + final ThumbnailsCacheManager.ThumbnailGenerationTask task = + new ThumbnailsCacheManager.ThumbnailGenerationTask( + 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(getFile()); + } } } @@ -307,8 +343,13 @@ public class PreviewImageFragment extends FileFragment { 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()); @@ -509,7 +550,12 @@ public class PreviewImageFragment extends FileFragment { imageView.setBackground(backrepeat); } - imageView.setImageBitmap(bitmap); + if (result.ocFile.getMimetype().equalsIgnoreCase("image/gif")){ + imageView.setGifImage(result.ocFile); + } else { + imageView.setImageBitmap(bitmap); + } + imageView.setVisibility(View.VISIBLE); mBitmap = bitmap; // needs to be kept for recycling when not useful } diff --git a/src/com/owncloud/android/ui/preview/PreviewImagePagerAdapter.java b/src/com/owncloud/android/ui/preview/PreviewImagePagerAdapter.java index dda7dda2..d6ea3479 100644 --- a/src/com/owncloud/android/ui/preview/PreviewImagePagerAdapter.java +++ b/src/com/owncloud/android/ui/preview/PreviewImagePagerAdapter.java @@ -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; @@ -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; @@ -104,17 +107,15 @@ public class PreviewImagePagerAdapter extends FragmentStatePagerAdapter { Fragment fragment = null; if (file.isDown()) { fragment = PreviewImageFragment.newInstance(file, - mObsoletePositions.contains(Integer.valueOf(i))); + mObsoletePositions.contains(Integer.valueOf(i)), false); } else if (mDownloadErrors.contains(Integer.valueOf(i))) { fragment = FileDownloadFragment.newInstance(file, mAccount, true); ((FileDownloadFragment)fragment).setError(true); mDownloadErrors.remove(Integer.valueOf(i)); - } else { - 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; diff --git a/src/com/owncloud/android/utils/DisplayUtils.java b/src/com/owncloud/android/utils/DisplayUtils.java index 99c465ec..f63d7ec4 100644 --- a/src/com/owncloud/android/utils/DisplayUtils.java +++ b/src/com/owncloud/android/utils/DisplayUtils.java @@ -22,9 +22,21 @@ package com.owncloud.android.utils; +import java.io.File; +import java.net.IDN; +import java.text.DateFormat; +import java.util.Arrays; +import java.util.Calendar; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; +import java.util.Vector; + import android.annotation.TargetApi; import android.app.Activity; import android.content.Context; +import android.content.SharedPreferences; import android.graphics.Point; import android.graphics.PorterDuff; import android.os.Build; @@ -35,6 +47,7 @@ import android.widget.SeekBar; import com.owncloud.android.MainApp; import com.owncloud.android.R; +import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; import java.math.BigDecimal; @@ -261,6 +274,67 @@ public class DisplayUtils { } /** + * Determines if user set folder to grid or list view. If folder is not set itself, + * it finds a parent that is set (at least root is set). + * @param file + * @param storageManager + * @return + */ + public static boolean isGridView(OCFile file, FileDataStorageManager storageManager){ + if (file != null) { + OCFile fileToTest = file; + OCFile parentDir = null; + String parentPath = null; + + SharedPreferences setting = MainApp.getAppContext().getSharedPreferences( + "viewMode", Context.MODE_PRIVATE); + + if (setting.contains(fileToTest.getRemoteId())) { + return setting.getBoolean(fileToTest.getRemoteId(), false); + } else { + do { + if (fileToTest.getParentId() != FileDataStorageManager.ROOT_PARENT_ID) { + parentPath = new File(fileToTest.getRemotePath()).getParent(); + parentPath = parentPath.endsWith(OCFile.PATH_SEPARATOR) ? parentPath : + parentPath + OCFile.PATH_SEPARATOR; + parentDir = storageManager.getFileByPath(parentPath); + } else { + parentDir = storageManager.getFileByPath(OCFile.ROOT_PATH); + } + + while (parentDir == null) { + parentPath = new File(parentPath).getParent(); + parentPath = parentPath.endsWith(OCFile.PATH_SEPARATOR) ? parentPath : + parentPath + OCFile.PATH_SEPARATOR; + parentDir = storageManager.getFileByPath(parentPath); + } + fileToTest = parentDir; + } while (endWhile(parentDir, setting)); + return setting.getBoolean(fileToTest.getRemoteId(), false); + } + } else { + return false; + } + } + + private static boolean endWhile(OCFile parentDir, SharedPreferences setting) { + if (parentDir.getRemotePath().compareToIgnoreCase(OCFile.ROOT_PATH) == 0) { + return false; + } else { + return !setting.contains(parentDir.getRemoteId()); + } + } + + public static void setViewMode(OCFile file, boolean setGrid){ + SharedPreferences setting = MainApp.getAppContext().getSharedPreferences( + "viewMode", Context.MODE_PRIVATE); + + SharedPreferences.Editor editor = setting.edit(); + editor.putBoolean(file.getRemoteId(), setGrid); + editor.commit(); + } + + /** * sets the coloring of the given progress bar to color_accent. * * @param progressBar the progress bar to be colored