From: tobiasKaminsky Date: Fri, 20 Nov 2015 17:32:55 +0000 (+0100) Subject: Merge remote-tracking branch 'remotes/upstream/externalSD2' into beta X-Git-Tag: beta-20151122~9 X-Git-Url: http://git.linex4red.de/pub/Android/ownCloud.git/commitdiff_plain/e35e32ad52f3964a44f0f404adf699e0d18502de?ds=inline;hp=-c Merge remote-tracking branch 'remotes/upstream/externalSD2' into beta --- e35e32ad52f3964a44f0f404adf699e0d18502de diff --combined AndroidManifest.xml index ad5dcfd5,ac57163c..12bd3f18 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@@ -16,10 -16,11 +16,10 @@@ You should have received a copy of the GNU General Public License along with this program. If not, see . ---> - + + android:versionName="ownCloud beta" xmlns:android="http://schemas.android.com/apk/res/android"> + + - + @@@ -115,7 -116,7 +117,7 @@@ 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" /> @@@ -126,12 -127,6 +128,12 @@@ android:exported="false" android:label="@string/search_users_and_groups_hint" /> + + + - - - - - - + + + + + + + + @@@ -183,10 -176,6 +185,10 @@@ + + + + diff --combined owncloud-android-library index 2e0f2a79,b09969d0..4f9a7528 --- a/owncloud-android-library +++ b/owncloud-android-library @@@ -1,1 -1,1 +1,1 @@@ - Subproject commit 2e0f2a79224383145d61cc15ca42c6bcc59902d5 -Subproject commit b09969d078b3a790b01c8d61a7298a37439a9f24 ++Subproject commit 4f9a7528cab0563cb234a8b817e8ee371dd6cc25 diff --combined res/values-hu-rHU/strings.xml index aea6f628,178d5950..25967de6 --- a/res/values-hu-rHU/strings.xml +++ b/res/values-hu-rHU/strings.xml @@@ -179,7 -179,7 +179,7 @@@ Nem kedvenc Átnevezés Eltávolítás - Tényleg el akarod távolítani %1$s? + Tényleg el akarod távolítani %1$s? Tényleg el akarod távolítani a %1$s és tartalmát? Csak a helyi példány Csak a helyi példány @@@ -192,6 -192,7 +192,7 @@@ Az állományok már szinkonizálva vannak A könyvtárt nem lehet létrehozni Nem megendedett karakterek: / \\ < > : \" | ? * + A fájlnév legalább egy érvénytelen karaktert tartalmaz! A fájl név nem lehet üres Egy pillanat... Váratlan hiba; válassza ki a fájlt más programból diff --combined res/values/strings.xml index 4e8f1800,4be03c1b..3750f610 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@@ -23,7 -23,8 +23,7 @@@ All files - + On device Settings Logs Close @@@ -61,7 -62,7 +61,7 @@@ Connect Upload New folder - Choose upload folder: + Choose upload folder No account found There are no %1$s accounts on your device. Please setup an account first. Setup @@@ -205,11 -206,11 +205,11 @@@ Unfavorite Rename Remove - "Do you really want to remove %1$s?" + "Do you really want to remove %1$s?" "Do you really want to remove %1$s and its contents?" Local only Local only - From server + From server Remote & local "Removal succeeded" "Removal failed" @@@ -265,11 -266,9 +265,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. @@@ -281,7 -280,7 +281,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. @@@ -314,6 -313,23 +314,23 @@@ to upload in this folder The file is no longer available on the server + Finish + Preparing for migration... + Checking destination... + Saving accounts configuration... + Waiting for unfinished synchronizations... + Moving data... + Updating index... + Cleaning... + Restoring accounts configuration... + Finished + ERROR: Not enough space + ERROR: File is not writable + ERROR: File is not readable + ERROR: owncloud directory already exists + ERROR: While migrating + ERROR: While updating index + Accounts Add account Secure connection is redirected through an unsecured route. @@@ -346,8 -362,7 +363,8 @@@ Instant Uploads Security - Upload Video Path + Upload video path + Download of %1$s folder could not be completed Synchronization of %1$s folder could not be completed shared @@@ -370,29 -385,9 +387,31 @@@ %1$d files %1$d files, 1 folder %1$d files, %2$d folders + Switch to grid view + Switch to list view + Common + Cache size + Upload file to server and ... + Behaviour + Copy file + Move file + Storage path + Common + do nothing + copy file to OC folder + move file to OC folder + delete origin file + Do you really want to remove selected items? + Do you really want to remove a folder and its content? + selected items + Exit + Send Log + Error Log + Stream file with external player + Do you want to stream this file with an external app?\n\nCAUTION: This may expose your password! + Set picture as + Sharing Share with Users and Groups No data shared with users yet @@@ -404,6 -399,5 +423,6 @@@ Sorry, your server version does not allow share with users within clients. \nPlease contact your administrator + https://github.com/owncloud/android/raw/beta/CHANGELOG.md diff --combined res/xml/preferences.xml index b4f46f98,e5908cf3..3972e9e3 --- a/res/xml/preferences.xml +++ b/res/xml/preferences.xml @@@ -3,7 -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,93 -18,57 +18,96 @@@ 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 --combined src/com/owncloud/android/MainApp.java index 6bf385ce,1cac7e53..401f6075 --- a/src/com/owncloud/android/MainApp.java +++ b/src/com/owncloud/android/MainApp.java @@@ -23,18 -23,19 +23,21 @@@ package com.owncloud.android import android.app.Activity; import android.app.Application; import android.content.Context; +import android.content.Intent; + import android.content.SharedPreferences; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.os.Build; import android.os.Bundle; + import android.os.Environment; + import android.preference.PreferenceManager; import com.owncloud.android.authentication.PassCodeManager; import com.owncloud.android.datamodel.ThumbnailsCacheManager; import com.owncloud.android.lib.common.OwnCloudClientManagerFactory; import com.owncloud.android.lib.common.OwnCloudClientManagerFactory.Policy; import com.owncloud.android.lib.common.utils.Log_OC; +import com.owncloud.android.utils.ExceptionHandler; /** @@@ -56,16 -57,22 +59,24 @@@ public class MainApp extends Applicatio private static Context mContext; + private static String storagePath; + - // TODO Enable when "On Device" is recovered? - // TODO better place - // private static boolean mOnlyOnDevice = false; + private static boolean mOnlyOnDevice = false; public void onCreate(){ super.onCreate(); MainApp.mContext = getApplicationContext(); + // Setup handler for uncaught exceptions. + Thread.setDefaultUncaughtExceptionHandler(new ExceptionHandler()); + ++ + SharedPreferences appPrefs = + PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); + MainApp.storagePath = appPrefs.getString("storage_path", Environment. + getExternalStorageDirectory().getAbsolutePath()); + boolean isSamlAuth = AUTH_ON.equals(getString(R.string.auth_method_saml_web_sso)); OwnCloudClientManagerFactory.setUserAgent(getUserAgent()); @@@ -85,7 -92,7 +96,7 @@@ // Set folder for store logs Log_OC.setLogDataFolder(dataFolder); - Log_OC.startLogging(); + Log_OC.startLogging(MainApp.storagePath); Log_OC.d("Debug", "start logging"); } @@@ -138,6 -145,14 +149,14 @@@ return MainApp.mContext; } + public static String getStoragePath(){ + return MainApp.storagePath; + } + + public static void setStoragePath(String path){ + MainApp.storagePath = path; + } + // Methods to obtain Strings referring app_name // From AccountAuthenticator // public static final String ACCOUNT_TYPE = "owncloud"; @@@ -179,13 -194,14 +198,13 @@@ return getAppContext().getResources().getString(R.string.log_name); } - // TODO Enable when "On Device" is recovered ? -// public static void showOnlyFilesOnDevice(boolean state){ -// mOnlyOnDevice = state; -// } -// -// public static boolean getOnlyOnDevice(){ -// return mOnlyOnDevice; -// } + public static void showOnlyFilesOnDevice(boolean state){ + mOnlyOnDevice = state; + } + + public static boolean getOnlyOnDevice(){ + return mOnlyOnDevice; + } // user agent public static String getUserAgent() { diff --combined src/com/owncloud/android/datamodel/FileDataStorageManager.java index 1ba669ee,dc24f343..cef10bc7 --- a/src/com/owncloud/android/datamodel/FileDataStorageManager.java +++ b/src/com/owncloud/android/datamodel/FileDataStorageManager.java @@@ -47,19 -47,12 +47,12 @@@ import android.provider.MediaStore import com.owncloud.android.MainApp; import com.owncloud.android.db.ProviderMeta.ProviderTableMeta; import com.owncloud.android.lib.common.utils.Log_OC; - import com.owncloud.android.lib.resources.files.FileUtils; import com.owncloud.android.lib.resources.shares.OCShare; import com.owncloud.android.lib.resources.shares.ShareType; import com.owncloud.android.lib.resources.status.CapabilityBooleanType; import com.owncloud.android.lib.resources.status.OCCapability; import com.owncloud.android.utils.FileStorageUtils; - import java.io.FileInputStream; - import java.io.FileOutputStream; - import java.io.IOException; - import java.io.InputStream; - import java.io.OutputStream; - public class FileDataStorageManager { public static final int ROOT_PARENT_ID = 0; @@@ -144,9 -137,10 +137,9 @@@ } - public Vector getFolderContent(OCFile f/*, boolean onlyOnDevice*/) { + public Vector getFolderContent(OCFile f, boolean onlyOnDevice) { if (f != null && f.isFolder() && f.getFileId() != -1) { - // TODO Enable when "On Device" is recovered ? - return getFolderContent(f.getFileId()/*, onlyOnDevice*/); + return getFolderContent(f.getFileId(), onlyOnDevice); } else { return new Vector(); @@@ -154,12 -148,13 +147,12 @@@ } - public Vector getFolderImages(OCFile folder/*, boolean onlyOnDevice*/) { - Vector ret = new Vector(); + public Vector getFolderImages(OCFile folder, boolean onlyOnDevice) { + Vector ret = new Vector(); if (folder != null) { // TODO better implementation, filtering in the access to database instead of here - // TODO Enable when "On Device" is recovered ? - Vector tmp = getFolderContent(folder/*, onlyOnDevice*/); - OCFile current = null; + Vector tmp = getFolderContent(folder, onlyOnDevice); + OCFile current = null; for (int i=0; i files = getFolderContent(folder.getFileId()/*, false*/); + Vector files = getFolderContent(folder.getFileId(), false); if (files != null) { for (OCFile file : files) { if (file.isFolder()) { @@@ -711,46 -707,77 +704,78 @@@ if (!targetFolder.exists()) { targetFolder.mkdirs(); } - copied = copyFile(localFile, targetFile); + copied = FileStorageUtils.copyFile(localFile, targetFile); } Log_OC.d(TAG, "Local file COPIED : " + copied); } } - private boolean copyFile(File src, File target) { - boolean ret = true; + public void migrateStoredFiles(String srcPath, String dstPath) throws Exception { + Cursor c = null; + if (getContentResolver() != null) { + c = getContentResolver().query(ProviderTableMeta.CONTENT_URI_FILE, + null, + ProviderTableMeta.FILE_STORAGE_PATH + " IS NOT NULL", + null, + null); + + } else { + try { + c = getContentProviderClient().query(ProviderTableMeta.CONTENT_URI_FILE, + new String[]{ProviderTableMeta._ID, ProviderTableMeta.FILE_STORAGE_PATH}, + ProviderTableMeta.FILE_STORAGE_PATH + " IS NOT NULL", + null, + null); + } catch (RemoteException e) { + Log_OC.e(TAG, e.getMessage()); + throw e; + } + } + + ArrayList operations = + new ArrayList(c.getCount()); + if (c.moveToFirst()) { + do { + ContentValues cv = new ContentValues(); + long fileId = c.getLong(c.getColumnIndex(ProviderTableMeta._ID)); + String oldFileStoragePath = c.getString(c.getColumnIndex(ProviderTableMeta.FILE_STORAGE_PATH)); + + if (oldFileStoragePath.startsWith(srcPath)) { + + cv.put( + ProviderTableMeta.FILE_STORAGE_PATH, + oldFileStoragePath.replaceFirst(srcPath, dstPath)); + + operations.add( + ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI). + withValues(cv). + withSelection( + ProviderTableMeta._ID + "=?", + new String[]{String.valueOf(fileId)} + ) + .build()); + } - InputStream in = null; - OutputStream out = null; + } while (c.moveToNext()); + } + c.close(); + /// 3. apply updates in batch try { - in = new FileInputStream(src); - out = new FileOutputStream(target); - byte[] buf = new byte[1024]; - int len; - while ((len = in.read(buf)) > 0) { - out.write(buf, 0, len); - } - } catch (IOException ex) { - ret = false; - } finally { - if (in != null) try { - in.close(); - } catch (IOException e) { - e.printStackTrace(System.err); - } - if (out != null) try { - out.close(); - } catch (IOException e) { - e.printStackTrace(System.err); + if (getContentResolver() != null) { + getContentResolver().applyBatch(MainApp.getAuthority(), operations); + + } else { + getContentProviderClient().applyBatch(operations); } - } - return ret; + } catch (Exception e) { + throw e; + } } - private Vector getFolderContent(long parentId/*, boolean onlyOnDevice*/) { + + private Vector getFolderContent(long parentId, boolean onlyOnDevice) { Vector ret = new Vector(); @@@ -777,9 -804,10 +802,9 @@@ if (c.moveToFirst()) { do { OCFile child = createFileInstance(c); - // TODO Enable when "On Device" is recovered ? - // if (child.isFolder() || !onlyOnDevice || onlyOnDevice && child.isDown()){ - ret.add(child); - // } + if (child.isFolder() || !onlyOnDevice || onlyOnDevice && child.isDown()){ + ret.add(child); + } } while (c.moveToNext()); } @@@ -1480,8 -1508,9 +1505,8 @@@ + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + "=?"; String [] whereArgs = new String[]{ "", mAccount.name }; - // TODO Enable when "On Device" is recovered ? - Vector files = getFolderContent(folder /*, false*/); - + Vector files = getFolderContent(folder, false); + for (OCFile file : files) { whereArgs[0] = file.getRemotePath(); preparedOperations.add( @@@ -1552,7 -1581,7 +1577,7 @@@ return shares; } - public void triggerMediaScan(String path) { + public static void triggerMediaScan(String path) { Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); intent.setData(Uri.fromFile(new File(path))); MainApp.getAppContext().sendBroadcast(intent); diff --combined src/com/owncloud/android/ui/activity/Preferences.java index 3f242c2d,3d5d8ab9..6d677cd3 --- a/src/com/owncloud/android/ui/activity/Preferences.java +++ b/src/com/owncloud/android/ui/activity/Preferences.java @@@ -34,8 -34,8 +34,9 @@@ import android.content.pm.PackageInfo import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Configuration; import android.net.Uri; +import android.os.AsyncTask; import android.os.Bundle; + import android.os.Environment; import android.os.Handler; import android.os.IBinder; import android.preference.CheckBoxPreference; @@@ -63,7 -63,6 +64,7 @@@ import android.widget.AdapterView.OnIte import android.widget.ArrayAdapter; import android.widget.ListAdapter; import android.widget.ListView; +import android.widget.Toast; import com.owncloud.android.BuildConfig; import com.owncloud.android.MainApp; @@@ -72,22 -71,17 +73,24 @@@ import com.owncloud.android.authenticat import com.owncloud.android.authentication.AuthenticatorActivity; import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; +import com.owncloud.android.datamodel.ThumbnailsCacheManager; import com.owncloud.android.db.DbHandler; import com.owncloud.android.files.FileOperationsHelper; import com.owncloud.android.files.services.FileDownloader; import com.owncloud.android.files.services.FileUploader; import com.owncloud.android.lib.common.utils.Log_OC; import com.owncloud.android.services.OperationsService; + import com.owncloud.android.ui.PreferenceWithLongSummary; import com.owncloud.android.ui.RadioButtonPreference; import com.owncloud.android.utils.DisplayUtils; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.concurrent.ExecutionException; + import java.io.File; /** @@@ -103,6 -97,8 +106,8 @@@ public class Preferences extends Prefer private static final int ACTION_SELECT_UPLOAD_PATH = 1; private static final int ACTION_SELECT_UPLOAD_VIDEO_PATH = 2; + private static final int ACTION_SELECT_STORAGE_PATH = 3; + private static final int ACTION_PERFORM_MIGRATION = 4; private DbHandler mDbHandler; private CheckBoxPreference pCode; @@@ -126,6 -122,8 +131,8 @@@ protected FileDownloader.FileDownloaderBinder mDownloaderBinder = null; protected FileUploader.FileUploaderBinder mUploaderBinder = null; private ServiceConnection mDownloadServiceConnection, mUploadServiceConnection = null; + private PreferenceWithLongSummary mPrefStoragePath; + private String mStoragePath; @SuppressWarnings("deprecation") @Override @@@ -247,31 -245,10 +254,31 @@@ } + final Preference pCacheSize = findPreference("pref_cache_size"); + if (pCacheSize != null){ + final SharedPreferences appPrefs = + PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); + Long cacheSize = ThumbnailsCacheManager.getMaxSize(); + pCacheSize.setSummary(cacheSize + " Mb"); + pCacheSize.setOnPreferenceChangeListener(new OnPreferenceChangeListener() { + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + Long size = Long.decode((String) newValue); + if (ThumbnailsCacheManager.setMaxSize(size)){ + appPrefs.edit().putString("pref_cache_size", size.toString()); + pCacheSize.setSummary(size + " MB"); + return true; + } else { + return false; + } + } + }); + } + PreferenceCategory preferenceCategory = (PreferenceCategory) findPreference("more"); boolean helpEnabled = getResources().getBoolean(R.bool.help_enabled); - Preference pHelp = findPreference("help"); + Preference pHelp = findPreference("help"); if (pHelp != null ){ if (helpEnabled) { pHelp.setOnPreferenceClickListener(new OnPreferenceClickListener() { @@@ -293,7 -270,7 +300,7 @@@ } if (BuildConfig.DEBUG) { - Preference pLog = findPreference("log"); + Preference pLog = findPreference("log"); if (pLog != null ){ pLog.setOnPreferenceClickListener(new OnPreferenceClickListener() { @Override @@@ -336,7 -313,7 +343,7 @@@ intent.putExtra(Intent.EXTRA_TEXT, recommendText); startActivity(intent); - return(true); + return true; } }); @@@ -353,9 -330,10 +360,10 @@@ pFeedback.setOnPreferenceClickListener(new OnPreferenceClickListener() { @Override public boolean onPreferenceClick(Preference preference) { - String feedbackMail =(String) getText(R.string.mail_feedback); - String feedback =(String) getText(R.string.prefs_feedback) + " - android v" + appVersion; - Intent intent = new Intent(Intent.ACTION_SENDTO); + String feedbackMail = (String) getText(R.string.mail_feedback); + String feedback = String.format("%s - android v%s", getText(R.string.prefs_feedback), appVersion); + Intent intent = new Intent(Intent.ACTION_SENDTO); + intent.setType("text/plain"); intent.putExtra(Intent.EXTRA_SUBJECT, feedback); @@@ -394,7 -372,29 +402,29 @@@ } } - mPrefInstantUploadPath = findPreference("instant_upload_path"); + mPrefStoragePath = (PreferenceWithLongSummary)findPreference("storage_path"); + if (mPrefStoragePath != null) { + + mPrefStoragePath.setOnPreferenceClickListener(new OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(Preference preference) { + Intent intent = new Intent(Preferences.this, LocalDirectorySelectorActivity.class); + intent.putExtra(UploadFilesActivity.KEY_DIRECTORY_PATH, mStoragePath); + startActivityForResult(intent, ACTION_SELECT_STORAGE_PATH); + return true; + } + }); + + mPrefStoragePath.setOnPreferenceChangeListener(new OnPreferenceChangeListener() { + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + MainApp.setStoragePath((String) newValue); + return true; + } + }); + } + + mPrefInstantUploadPath = (PreferenceWithLongSummary)findPreference("instant_upload_path"); if (mPrefInstantUploadPath != null){ mPrefInstantUploadPath.setOnPreferenceClickListener(new OnPreferenceClickListener() { @@@ -414,7 -414,7 +444,7 @@@ mPrefInstantUploadCategory = (PreferenceCategory) findPreference("instant_uploading_category"); - mPrefInstantUploadPathWiFi = findPreference("instant_upload_on_wifi"); + mPrefInstantUploadPathWiFi = findPreference("instant_upload_on_wifi"); mPrefInstantUpload = findPreference("instant_uploading"); toggleInstantPictureOptions(((CheckBoxPreference) mPrefInstantUpload).isChecked()); @@@ -460,20 -460,14 +490,21 @@@ }); /* About App */ - pAboutApp = (Preference) findPreference("about_app"); + pAboutApp = findPreference("about_app"); if (pAboutApp != null) { - pAboutApp.setTitle(String.format(getString(R.string.about_android), getString(R.string.app_name))); - pAboutApp.setSummary(String.format(getString(R.string.about_version), appVersion)); + pAboutApp.setTitle(String.format(getString(R.string.about_android), + getString(R.string.app_name))); + try { + Integer currentVersion = getPackageManager().getPackageInfo + (getPackageName(), 0).versionCode; + pAboutApp.setSummary(String.format(getString(R.string.about_version), + currentVersion)); + } catch (NameNotFoundException e) { + } } loadInstantUploadPath(); + loadStoragePath(); loadInstantUploadVideoPath(); /* ComponentsGetter */ @@@ -488,65 -482,6 +519,65 @@@ Context.BIND_AUTO_CREATE); } + /* Link to Beta apks */ + Preference pBetaLink = findPreference("beta_link"); + if (pBetaLink != null ){ + pBetaLink.setOnPreferenceClickListener(new OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(Preference preference) { + Integer latestVersion = -1; + Integer currentVersion = -1; + try { + currentVersion = getPackageManager().getPackageInfo + (getPackageName(), 0).versionCode; + LoadingVersionNumberTask loadTask = new LoadingVersionNumberTask(); + loadTask.execute(); + latestVersion = loadTask.get(); + } catch (InterruptedException | ExecutionException e) { + e.printStackTrace(); + } catch (NameNotFoundException e) { + e.printStackTrace(); + } + if (latestVersion == -1 || currentVersion == -1) { + Toast.makeText(getApplicationContext(), "No information available!", + Toast.LENGTH_SHORT).show(); + } + if (latestVersion > currentVersion) { + String betaLinkWeb = (String) getText(R.string.beta_link) + + latestVersion + ".apk"; + if (betaLinkWeb != null && betaLinkWeb.length() > 0) { + Uri uriUrl = Uri.parse(betaLinkWeb); + Intent intent = new Intent(Intent.ACTION_VIEW, uriUrl); + startActivity(intent); + return true; + } + } else { + Toast.makeText(getApplicationContext(), "No new version available!", + Toast.LENGTH_SHORT).show(); + return true; + } + return true; + } + }); + } + + /* Link to Beta apks */ + Preference pChangelogLink = findPreference("changelog_link"); + if (pChangelogLink != null) { + pChangelogLink.setOnPreferenceClickListener(new OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(Preference preference) { + String betaLinkWeb = getString(R.string.changelog); + if (betaLinkWeb != null && betaLinkWeb.length() > 0) { + Uri uriUrl = Uri.parse(betaLinkWeb); + Intent intent = new Intent(Intent.ACTION_VIEW, uriUrl); + startActivity(intent); + return true; + } + return true; + } + }); + } } private void toggleInstantPictureOptions(Boolean value){ @@@ -554,8 -489,8 +585,8 @@@ mPrefInstantUploadCategory.addPreference(mPrefInstantUploadPathWiFi); mPrefInstantUploadCategory.addPreference(mPrefInstantUploadPath); } else { - mPrefInstantUploadCategory.removePreference(mPrefInstantUploadPathWiFi); - mPrefInstantUploadCategory.removePreference(mPrefInstantUploadPath); +// mPrefInstantUploadCategory.removePreference(mPrefInstantUploadPathWiFi); +// mPrefInstantUploadCategory.removePreference(mPrefInstantUploadPath); } } @@@ -564,8 -499,8 +595,8 @@@ mPrefInstantUploadCategory.addPreference(mPrefInstantVideoUploadPathWiFi); mPrefInstantUploadCategory.addPreference(mPrefInstantVideoUploadPath); } else { - mPrefInstantUploadCategory.removePreference(mPrefInstantVideoUploadPathWiFi); - mPrefInstantUploadCategory.removePreference(mPrefInstantVideoUploadPath); +// mPrefInstantUploadCategory.removePreference(mPrefInstantVideoUploadPathWiFi); +// mPrefInstantUploadCategory.removePreference(mPrefInstantVideoUploadPath); } } @@@ -651,8 -586,7 +682,7 @@@ if (requestCode == ACTION_SELECT_UPLOAD_PATH && resultCode == RESULT_OK){ - OCFile folderToUpload = - (OCFile) data.getParcelableExtra(UploadPathActivity.EXTRA_FOLDER); + OCFile folderToUpload = data.getParcelableExtra(UploadPathActivity.EXTRA_FOLDER); mUploadPath = folderToUpload.getRemotePath(); @@@ -663,10 -597,9 +693,9 @@@ saveInstantUploadPathOnPreferences(); - } else if (requestCode == ACTION_SELECT_UPLOAD_VIDEO_PATH && resultCode == RESULT_OK){ + } else if (requestCode == ACTION_SELECT_UPLOAD_VIDEO_PATH && resultCode == RESULT_OK) { - OCFile folderToUploadVideo = - (OCFile) data.getParcelableExtra(UploadPathActivity.EXTRA_FOLDER); + OCFile folderToUploadVideo = data.getParcelableExtra(UploadPathActivity.EXTRA_FOLDER); mUploadVideoPath = folderToUploadVideo.getRemotePath(); @@@ -676,6 -609,21 +705,21 @@@ mPrefInstantVideoUploadPath.setSummary(mUploadVideoPath); saveInstantUploadVideoPathOnPreferences(); + } else if (requestCode == ACTION_SELECT_STORAGE_PATH && resultCode == RESULT_OK) { + File currentStorageDir = new File(mStoragePath); + File upcomingStorageDir = new File(data.getStringExtra(UploadFilesActivity.EXTRA_CHOSEN_FILES)); + + if (currentStorageDir != upcomingStorageDir) { + Intent migrationIntent = new Intent(this, StorageMigrationActivity.class); + migrationIntent.putExtra(StorageMigrationActivity.KEY_MIGRATION_SOURCE_DIR, + currentStorageDir.getAbsolutePath()); + migrationIntent.putExtra(StorageMigrationActivity.KEY_MIGRATION_TARGET_DIR, + upcomingStorageDir.getAbsolutePath()); + startActivityForResult(migrationIntent, ACTION_PERFORM_MIGRATION); + } + } else if (requestCode == ACTION_PERFORM_MIGRATION && resultCode == RESULT_OK) { + String resultStorageDir = data.getStringExtra(StorageMigrationActivity.KEY_MIGRATION_TARGET_DIR); + saveStoragePath(resultStorageDir); } } @@@ -700,7 -648,6 +744,7 @@@ public void setContentView(View view) { getDelegate().setContentView(view); } + @Override public void setContentView(View view, ViewGroup.LayoutParams params) { getDelegate().setContentView(view, params); @@@ -886,6 -833,31 +930,31 @@@ } /** + * Save storage path + */ + private void saveStoragePath(String newStoragePath) { + SharedPreferences appPrefs = + PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); + mStoragePath = newStoragePath; + MainApp.setStoragePath(mStoragePath); + SharedPreferences.Editor editor = appPrefs.edit(); + editor.putString("storage_path", mStoragePath); + editor.commit(); + mPrefStoragePath.setSummary(mStoragePath); + } + + /** + * Load storage path set on preferences + */ + private void loadStoragePath() { + SharedPreferences appPrefs = + PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); + mStoragePath = appPrefs.getString("storage_path", Environment.getExternalStorageDirectory() + .getAbsolutePath()); + mPrefStoragePath.setSummary(mStoragePath); + } + + /** * Save the "Instant Upload Path" on preferences */ private void saveInstantUploadPathOnPreferences() { @@@ -900,10 -872,7 +969,7 @@@ * Load upload video path set on preferences */ private void loadInstantUploadVideoPath() { - SharedPreferences appPrefs = - PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); - mUploadVideoPath = appPrefs.getString("instant_video_upload_path", getString(R.string.instant_upload_path)); - mPrefInstantVideoUploadPath.setSummary(mUploadVideoPath); + mPrefInstantVideoUploadPath.setSummary(MainApp.getStoragePath()); } /** @@@ -917,7 -886,7 +983,7 @@@ editor.commit(); } - // Methods for ComponetsGetter + // Methods for ComponentsGetter @Override public FileDownloader.FileDownloaderBinder getFileDownloaderBinder() { return mDownloaderBinder; @@@ -956,14 -925,10 +1022,10 @@@ if (component.equals(new ComponentName(Preferences.this, FileDownloader.class))) { mDownloaderBinder = (FileDownloader.FileDownloaderBinder) service; - } else if (component.equals(new ComponentName(Preferences.this, FileUploader.class))) { Log_OC.d(TAG, "Upload service connected"); mUploaderBinder = (FileUploader.FileUploaderBinder) service; - } else { - return; } - } @Override @@@ -977,29 -942,4 +1039,29 @@@ } } }; + + /** + * + * Class for loading the version number + * + */ + private class LoadingVersionNumberTask extends AsyncTask { + protected Integer doInBackground(Void... args) { + try { + URL url = new URL("https://github.com/owncloud/android/raw/beta/apks/latest"); + BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream())); + + Integer latestVersion = Integer.parseInt(in.readLine()); + in.close(); + + return latestVersion; + + } catch (MalformedURLException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + return -1; + } + } } diff --combined src/com/owncloud/android/ui/activity/UploadFilesActivity.java index f93af1f3,bf1a204d..d6665e2b --- a/src/com/owncloud/android/ui/activity/UploadFilesActivity.java +++ b/src/com/owncloud/android/ui/activity/UploadFilesActivity.java @@@ -21,29 -21,21 +21,29 @@@ package com.owncloud.android.ui.activity; import android.accounts.Account; +import android.app.AlertDialog; +import android.content.DialogInterface; import android.content.Intent; +import android.content.SharedPreferences; import android.os.AsyncTask; import android.os.Bundle; import android.os.Environment; +import android.preference.PreferenceManager; import android.support.v4.app.DialogFragment; import android.support.v7.app.ActionBar; +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; import android.widget.ArrayAdapter; import android.widget.Button; +import android.widget.RadioButton; import android.widget.TextView; import com.owncloud.android.R; +import com.owncloud.android.files.services.FileUploader; import com.owncloud.android.lib.common.utils.Log_OC; import com.owncloud.android.ui.dialog.ConfirmationDialogFragment; import com.owncloud.android.ui.dialog.ConfirmationDialogFragment.ConfirmationDialogFragmentListener; @@@ -65,34 -57,33 +65,35 @@@ public class UploadFilesActivity extend private ArrayAdapter mDirectories; private File mCurrentDir = null; - private LocalFileListFragment mFileListFragment; - private Button mCancelBtn; - private Button mUploadBtn; - private Account mAccountOnCreation; - private DialogFragment mCurrentDialog; + protected LocalFileListFragment mFileListFragment; + protected Button mCancelBtn; + protected Button mUploadBtn; + protected Account mAccountOnCreation; + protected DialogFragment mCurrentDialog; public static final String EXTRA_CHOSEN_FILES = UploadFilesActivity.class.getCanonicalName() + ".EXTRA_CHOSEN_FILES"; public static final int RESULT_OK_AND_MOVE = RESULT_FIRST_USER; - private static final String KEY_DIRECTORY_PATH = + public static final String KEY_DIRECTORY_PATH = UploadFilesActivity.class.getCanonicalName() + ".KEY_DIRECTORY_PATH"; private static final String TAG = "UploadFilesActivity"; private static final String WAIT_DIALOG_TAG = "WAIT"; private static final String QUERY_TO_MOVE_DIALOG_TAG = "QUERY_TO_MOVE"; - - + private RadioButton mRadioBtnCopyFiles; + private RadioButton mRadioBtnMoveFiles; + + @Override public void onCreate(Bundle savedInstanceState) { Log_OC.d(TAG, "onCreate() start"); super.onCreate(savedInstanceState); if(savedInstanceState != null) { - mCurrentDir = new File(savedInstanceState.getString( - UploadFilesActivity.KEY_DIRECTORY_PATH)); + mCurrentDir = new File(savedInstanceState.getString(KEY_DIRECTORY_PATH)); + } else if (getIntent() != null && getIntent().hasExtra(KEY_DIRECTORY_PATH)) { + mCurrentDir = new File(getIntent().getStringExtra(KEY_DIRECTORY_PATH)); } else { mCurrentDir = Environment.getExternalStorageDirectory(); } @@@ -122,21 -113,6 +123,21 @@@ mCancelBtn.setOnClickListener(this); mUploadBtn = (Button) findViewById(R.id.upload_files_btn_upload); mUploadBtn.setOnClickListener(this); + + SharedPreferences appPreferences = PreferenceManager + .getDefaultSharedPreferences(getApplicationContext()); + + Integer localBehaviour = appPreferences.getInt("prefs_uploader_behaviour", FileUploader.LOCAL_BEHAVIOUR_COPY); + + mRadioBtnMoveFiles = (RadioButton) findViewById(R.id.upload_radio_move); + if (localBehaviour == FileUploader.LOCAL_BEHAVIOUR_MOVE){ + mRadioBtnMoveFiles.setChecked(true); + } + + mRadioBtnCopyFiles = (RadioButton) findViewById(R.id.upload_radio_copy); + if (localBehaviour == FileUploader.LOCAL_BEHAVIOUR_COPY){ + mRadioBtnCopyFiles.setChecked(true); + } // Action bar setup @@@ -157,13 -133,6 +158,13 @@@ Log_OC.d(TAG, "onCreate() end"); } + @Override + public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.uploader_menu, menu); + return true; + } + @Override public boolean onOptionsItemSelected(MenuItem item) { @@@ -175,34 -144,6 +176,34 @@@ } break; } + case R.id.action_sort: { + SharedPreferences appPreferences = PreferenceManager + .getDefaultSharedPreferences(this); + + // Read sorting order, default to sort by name ascending + Integer sortOrder = appPreferences + .getInt("sortOrder", FileStorageUtils.SORT_NAME); + + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(R.string.actionbar_sort_title) + .setSingleChoiceItems(R.array.actionbar_sortby, sortOrder , + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + switch (which){ + case 0: + mFileListFragment.sortByName(true); + break; + case 1: + mFileListFragment.sortByDate(false); + break; + } + + dialog.dismiss(); + } + }); + builder.create().show(); + break; + } default: retval = super.onOptionsItemSelected(item); } @@@ -402,22 -343,9 +403,22 @@@ // return the list of selected files (success) Intent data = new Intent(); data.putExtra(EXTRA_CHOSEN_FILES, mFileListFragment.getCheckedFilePaths()); - setResult(RESULT_OK, data); + + SharedPreferences.Editor appPreferencesEditor = PreferenceManager + .getDefaultSharedPreferences(getApplicationContext()).edit(); + + + if (mRadioBtnMoveFiles.isChecked()){ + setResult(RESULT_OK_AND_MOVE, data); + appPreferencesEditor.putInt("prefs_uploader_behaviour", + FileUploader.LOCAL_BEHAVIOUR_MOVE); + } else { + setResult(RESULT_OK, data); + appPreferencesEditor.putInt("prefs_uploader_behaviour", + FileUploader.LOCAL_BEHAVIOUR_COPY); + } + appPreferencesEditor.apply(); finish(); - } else { // show a dialog to query the user if wants to move the selected files // to the ownCloud folder instead of copying diff --combined src/com/owncloud/android/utils/FileStorageUtils.java index 47a46d2c,e93ead0d..e300a5e2 --- a/src/com/owncloud/android/utils/FileStorageUtils.java +++ b/src/com/owncloud/android/utils/FileStorageUtils.java @@@ -21,11 -21,13 +21,16 @@@ package com.owncloud.android.utils; import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; + import java.io.FileInputStream; + import java.io.FileOutputStream; + import java.io.IOException; + import java.io.InputStream; + import java.io.OutputStream; import java.util.Collections; import java.util.Comparator; +import java.util.List; import java.util.Vector; import third_parties.daveKoeller.AlphanumComparator; @@@ -41,7 -43,6 +46,6 @@@ import android.content.Context import android.content.SharedPreferences; import android.preference.PreferenceManager; import android.net.Uri; - import android.os.Environment; import android.os.StatFs; import android.webkit.MimeTypeMap; @@@ -58,8 -59,9 +62,9 @@@ public class FileStorageUtils public static final String getSavePath(String accountName) { - File sdCard = Environment.getExternalStorageDirectory(); - return sdCard.getAbsolutePath() + "/" + MainApp.getDataFolder() + "/" + Uri.encode(accountName, "@"); + // File sdCard = Environment.getExternalStorageDirectory(); + + return MainApp.getStoragePath() + File.separator + MainApp.getDataFolder() + File.separator + Uri.encode(accountName, "@"); // URL encoding is an 'easy fix' to overcome that NTFS and FAT32 don't allow ":" in file names, that can be in the accountName since 0.1.190B } @@@ -68,14 -70,13 +73,13 @@@ } public static final String getTemporalPath(String accountName) { - File sdCard = Environment.getExternalStorageDirectory(); - return sdCard.getAbsolutePath() + "/" + MainApp.getDataFolder() + "/tmp/" + Uri.encode(accountName, "@"); + return MainApp.getStoragePath() + File.separator + MainApp.getDataFolder() + File.separator + "tmp" + File.separator + Uri.encode(accountName, "@"); // URL encoding is an 'easy fix' to overcome that NTFS and FAT32 don't allow ":" in file names, that can be in the accountName since 0.1.190B } @SuppressLint("NewApi") public static final long getUsableSpace(String accountName) { - File savePath = Environment.getExternalStorageDirectory(); + File savePath = new File(MainApp.getStoragePath()); if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.GINGERBREAD) { return savePath.getUsableSpace(); @@@ -87,7 -88,7 +91,7 @@@ } public static final String getLogPath() { - return Environment.getExternalStorageDirectory() + File.separator + MainApp.getDataFolder() + File.separator + "log"; + return MainApp.getStoragePath() + File.separator + MainApp.getDataFolder() + File.separator + "log"; } public static String getInstantUploadFilePath(Context context, String fileName) { @@@ -157,13 -158,13 +161,13 @@@ /** * Sorts all filenames, regarding last user decision */ - public static Vector sortFolder(Vector files){ + public static Vector sortOcFolder(Vector files){ switch (mSortOrder){ case 0: - files = FileStorageUtils.sortByName(files); + files = FileStorageUtils.sortOCFilesByName(files); break; case 1: - files = FileStorageUtils.sortByDate(files); + files = FileStorageUtils.sortOCFilesByDate(files); break; case 2: // mFiles = FileStorageUtils.sortBySize(mSortAscending); @@@ -172,31 -173,12 +176,31 @@@ return files; } + + /** + * Sorts all filenames, regarding last user decision + */ + public static File[] sortLocalFolder(File[] files){ + switch (mSortOrder){ + case 0: + files = FileStorageUtils.sortLocalFilesByName(files); + break; + case 1: + files = FileStorageUtils.sortLocalFilesByDate(files); + break; + case 2: + // mFiles = FileStorageUtils.sortBySize(mSortAscending); + break; + } + + return files; + } /** * Sorts list by Date * @param files */ - public static Vector sortByDate(Vector files){ + public static Vector sortOCFilesByDate(Vector files){ final Integer val; if (mSortAscending){ val = 1; @@@ -226,43 -208,6 +230,43 @@@ return files; } + /** + * Sorts list by Date + * @param filesArray + */ + public static File[] sortLocalFilesByDate(File[] filesArray){ + final Integer val; + if (mSortAscending){ + val = 1; + } else { + val = -1; + } + + List files = new ArrayList(Arrays.asList(filesArray)); + + Collections.sort(files, new Comparator() { + public int compare(File o1, File o2) { + if (o1.isDirectory() && o2.isDirectory()) { + Long obj1 = o1.lastModified(); + return val * obj1.compareTo(o2.lastModified()); + } + else if (o1.isDirectory()) { + return -1; + } else if (o2.isDirectory()) { + return 1; + } else if (o1.lastModified() == 0 || o2.lastModified() == 0){ + return 0; + } else { + Long obj1 = o1.lastModified(); + return val * obj1.compareTo(o2.lastModified()); + } + } + }); + + File[] returnArray = new File[1]; + return files.toArray(returnArray); + } + // /** // * Sorts list by Size // * @param sortAscending true: ascending, false: descending @@@ -301,7 -246,7 +305,7 @@@ * Sorts list by Name * @param files files to sort */ - public static Vector sortByName(Vector files){ + public static Vector sortOCFilesByName(Vector files){ final Integer val; if (mSortAscending){ val = 1; @@@ -324,38 -269,6 +328,38 @@@ return files; } + + /** + * Sorts list by Name + * @param filesArray files to sort + */ + public static File[] sortLocalFilesByName(File[] filesArray){ + final Integer val; + if (mSortAscending){ + val = 1; + } else { + val = -1; + } + + List files = new ArrayList(Arrays.asList(filesArray)); + + Collections.sort(files, new Comparator() { + public int compare(File o1, File o2) { + if (o1.isDirectory() && o2.isDirectory()) { + return val * o1.getPath().toLowerCase().compareTo(o2.getPath().toLowerCase()); + } else if (o1.isDirectory()) { + return -1; + } else if (o2.isDirectory()) { + return 1; + } + return val * new AlphanumComparator().compare(o1.getPath().toLowerCase(), + o2.getPath().toLowerCase()); + } + }); + + File[] returnArray = new File[1]; + return files.toArray(returnArray); + } /** * Local Folder size @@@ -365,13 -278,11 +369,11 @@@ public static long getFolderSize(File dir) { if (dir.exists()) { long result = 0; - File[] fileList = dir.listFiles(); - for(int i = 0; i < fileList.length; i++) { - if(fileList[i].isDirectory()) { - result += getFolderSize(fileList[i]); - } else { - result += fileList[i].length(); - } + for (File f : dir.listFiles()) { + if (f.isDirectory()) + result += getFolderSize(f); + else + result += f.length(); } return result; } @@@ -421,4 -332,36 +423,36 @@@ } } + public static boolean copyFile(File src, File target) { + boolean ret = true; + + InputStream in = null; + OutputStream out = null; + + try { + in = new FileInputStream(src); + out = new FileOutputStream(target); + byte[] buf = new byte[1024]; + int len; + while ((len = in.read(buf)) > 0) { + out.write(buf, 0, len); + } + } catch (IOException ex) { + ret = false; + } finally { + if (in != null) try { + in.close(); + } catch (IOException e) { + e.printStackTrace(System.err); + } + if (out != null) try { + out.close(); + } catch (IOException e) { + e.printStackTrace(System.err); + } + } + + return ret; + } + }