From 31ffae009339abef016eb5e61d2ec5d081446717 Mon Sep 17 00:00:00 2001 From: grecep Date: Wed, 29 Oct 2014 22:37:45 +0100 Subject: [PATCH 01/16] Revert "Add "select all" option to photo (or other) upload screen" --- res/menu/file_select_all.xml | 11 ----- .../ui/activity/UploadFilesActivity.java | 44 ++----------------- .../ui/fragment/LocalFileListFragment.java | 22 +--------- tests/.classpath | 4 +- 4 files changed, 7 insertions(+), 74 deletions(-) delete mode 100644 res/menu/file_select_all.xml diff --git a/res/menu/file_select_all.xml b/res/menu/file_select_all.xml deleted file mode 100644 index a8097aae22..0000000000 --- a/res/menu/file_select_all.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - diff --git a/src/com/owncloud/android/ui/activity/UploadFilesActivity.java b/src/com/owncloud/android/ui/activity/UploadFilesActivity.java index 83e7bc073e..0918572697 100644 --- a/src/com/owncloud/android/ui/activity/UploadFilesActivity.java +++ b/src/com/owncloud/android/ui/activity/UploadFilesActivity.java @@ -34,9 +34,6 @@ import android.widget.TextView; import com.actionbarsherlock.app.ActionBar; import com.actionbarsherlock.app.ActionBar.OnNavigationListener; -import com.actionbarsherlock.internal.view.menu.ActionMenuItemView; -import com.actionbarsherlock.view.Menu; -import com.actionbarsherlock.view.MenuInflater; import com.actionbarsherlock.view.MenuItem; import com.owncloud.android.R; import com.owncloud.android.lib.common.utils.Log_OC; @@ -76,8 +73,6 @@ public class UploadFilesActivity extends FileActivity implements private static final String WAIT_DIALOG_TAG = "WAIT"; private static final String QUERY_TO_MOVE_DIALOG_TAG = "QUERY_TO_MOVE"; - private boolean selectAllToggled = false; - private Menu menu; @Override public void onCreate(Bundle savedInstanceState) { @@ -124,7 +119,6 @@ public class UploadFilesActivity extends FileActivity implements actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST); actionBar.setListNavigationCallbacks(mDirectories, this); - // wait dialog if (mCurrentDialog != null) { mCurrentDialog.dismiss(); @@ -133,15 +127,8 @@ public class UploadFilesActivity extends FileActivity implements Log_OC.d(TAG, "onCreate() end"); } - @Override - public boolean onCreateOptionsMenu(Menu menu) { - // Inflate the menu items for use in the action bar - MenuInflater inflater = getSherlock().getMenuInflater(); - inflater.inflate(R.menu.file_select_all, menu); - this.menu = menu; - return true; - } - + + @Override public boolean onOptionsItemSelected(MenuItem item) { boolean retval = true; @@ -152,33 +139,12 @@ public class UploadFilesActivity extends FileActivity implements } break; } - case R.id.actionbar_select_all:{ - if(selectAllToggled){ - toggleOffSelectAll(); - }else{ - toggleOnSelectAll(item); - } - break; - } default: retval = super.onOptionsItemSelected(item); } return retval; } - public void toggleOffSelectAll(MenuItem item){ - selectAllToggled = false; - item.setIcon(android.R.drawable.checkbox_off_background); - mFileListFragment.deselectAll(); - } - public void toggleOffSelectAll(){ - MenuItem item = menu.findItem(R.id.actionbar_select_all); - toggleOffSelectAll(item); - } - public void toggleOnSelectAll(MenuItem item){ - selectAllToggled = true; - item.setIcon(android.R.drawable.checkbox_on_background); - mFileListFragment.selectAll(); - } + @Override public boolean onNavigationItemSelected(int itemPosition, long itemId) { @@ -209,7 +175,6 @@ public class UploadFilesActivity extends FileActivity implements ActionBar actionBar = getSupportActionBar(); actionBar.setDisplayHomeAsUpEnabled(false); } - toggleOffSelectAll(); } @@ -277,11 +242,10 @@ public class UploadFilesActivity extends FileActivity implements * {@inheritDoc} */ @Override - public void onDirectoryClick(File directory) { + public void onDirectoryClick(File directory) { pushDirname(directory); ActionBar actionBar = getSupportActionBar(); actionBar.setDisplayHomeAsUpEnabled(true); - toggleOffSelectAll(); } diff --git a/src/com/owncloud/android/ui/fragment/LocalFileListFragment.java b/src/com/owncloud/android/ui/fragment/LocalFileListFragment.java index 62b41a3ebf..c9408b1e5b 100644 --- a/src/com/owncloud/android/ui/fragment/LocalFileListFragment.java +++ b/src/com/owncloud/android/ui/fragment/LocalFileListFragment.java @@ -98,33 +98,13 @@ public class LocalFileListFragment extends ExtendedListFragment { Log_OC.i(TAG, "onActivityCreated() stop"); } - public void selectAll(){ - int numberOfFiles = mAdapter.getCount(); - for(int i = 0; i < numberOfFiles; i++){ - File file = (File) mAdapter.getItem(i); - if (file != null) { - if (!file.isDirectory()) { - /// Click on a file - getListView().setItemChecked(i, true); - // notify the change to the container Activity - mContainerActivity.onFileClick(file); - } - } - } - } - - public void deselectAll(){ - mAdapter = new LocalFileListAdapter(mContainerActivity.getInitialDirectory(), getActivity()); - setListAdapter(mAdapter); - } /** * Checks the file clicked over. Browses inside if it is a directory. Notifies the container activity in any case. */ @Override public void onItemClick(AdapterView l, View v, int position, long id) { - File file = (File) mAdapter.getItem(position); - + File file = (File) mAdapter.getItem(position); if (file != null) { /// Click on a directory if (file.isDirectory()) { diff --git a/tests/.classpath b/tests/.classpath index 26d8fe4850..9b141f6f1c 100644 --- a/tests/.classpath +++ b/tests/.classpath @@ -1,10 +1,10 @@ + + - - From da7e13ed5ce67e0da36963cf87ccb3e9610270ee Mon Sep 17 00:00:00 2001 From: jabarros Date: Fri, 7 Nov 2014 14:57:47 +0100 Subject: [PATCH 02/16] Include impelementation of Storage Access Framework when device is KITKAT or over --- .../ui/activity/FileDisplayActivity.java | 147 ++++++++++++++++-- 1 file changed, 135 insertions(+), 12 deletions(-) diff --git a/src/com/owncloud/android/ui/activity/FileDisplayActivity.java b/src/com/owncloud/android/ui/activity/FileDisplayActivity.java index b5d543a4e2..ad6a072a86 100644 --- a/src/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/src/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -31,6 +31,7 @@ import android.app.ProgressDialog; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ContentResolver; +import android.content.ContentUris; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; @@ -41,9 +42,12 @@ import android.content.SyncRequest; import android.content.res.Resources.NotFoundException; import android.database.Cursor; import android.net.Uri; +import android.os.Build; import android.os.Bundle; +import android.os.Environment; import android.os.IBinder; import android.preference.PreferenceManager; +import android.provider.DocumentsContract; import android.provider.MediaStore; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; @@ -866,25 +870,144 @@ OnSslUntrustedCertListener, OnEnforceableRefreshListener { return dialog; } - /** - * Translates a content URI of an image to a physical path - * on the disk + * Translates a content URI of an content to a physical path on the disk + * * @param uri The URI to resolve - * @return The path to the image or null if it could not be found + * @return The path to the content or null if it could not be found */ public String getPath(Uri uri) { - String[] projection = { MediaStore.Images.Media.DATA }; - Cursor cursor = managedQuery(uri, projection, null, null, null); - if (cursor != null) { - int column_index = cursor - .getColumnIndexOrThrow(MediaStore.Images.Media.DATA); - cursor.moveToFirst(); - return cursor.getString(column_index); - } + final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT; + + // DocumentProvider + if (isKitKat && DocumentsContract.isDocumentUri(getApplicationContext(), uri)) { + // ExternalStorageProvider + if (isExternalStorageDocument(uri)) { + final String docId = DocumentsContract.getDocumentId(uri); + final String[] split = docId.split(":"); + final String type = split[0]; + + if ("primary".equalsIgnoreCase(type)) { + return Environment.getExternalStorageDirectory() + "/" + split[1]; + } + } + // DownloadsProvider + else if (isDownloadsDocument(uri)) { + + final String id = DocumentsContract.getDocumentId(uri); + final Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), + Long.valueOf(id)); + + return getDataColumn(getApplicationContext(), contentUri, null, null); + } + // MediaProvider + else if (isMediaDocument(uri)) { + final String docId = DocumentsContract.getDocumentId(uri); + final String[] split = docId.split(":"); + final String type = split[0]; + + Uri contentUri = null; + if ("image".equals(type)) { + contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; + } else if ("video".equals(type)) { + contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; + } else if ("audio".equals(type)) { + contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; + } + + final String selection = "_id=?"; + final String[] selectionArgs = new String[] { split[1] }; + + return getDataColumn(getApplicationContext(), contentUri, selection, selectionArgs); + } + } + // MediaStore (and general) + else if ("content".equalsIgnoreCase(uri.getScheme())) { + + // Return the remote address + if (isGooglePhotosUri(uri)) + return uri.getLastPathSegment(); + + return getDataColumn(getApplicationContext(), uri, null, null); + } + // File + else if ("file".equalsIgnoreCase(uri.getScheme())) { + return uri.getPath(); + } return null; } + /** + * Get the value of the data column for this Uri. This is useful for + * MediaStore Uris, and other file-based ContentProviders. + * + * @param context The context. + * @param uri The Uri to query. + * @param selection (Optional) Filter used in the query. + * @param selectionArgs (Optional) Selection arguments used in the query. + * @return The value of the _data column, which is typically a file path. + */ + public static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) { + + Cursor cursor = null; + final String column = "_data"; + final String[] projection = { column }; + + try { + cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null); + if (cursor != null && cursor.moveToFirst()) { + + final int column_index = cursor.getColumnIndexOrThrow(column); + return cursor.getString(column_index); + } + } finally { + if (cursor != null) + cursor.close(); + } + return null; + } + + /** + * @param uri The Uri to check. + * @return Whether the Uri authority is ExternalStorageProvider. + */ + public static boolean isExternalStorageDocument(Uri uri) { + return "com.android.externalstorage.documents".equals(uri.getAuthority()); + } + + /** + * @param uri The Uri to check. + * @return Whether the Uri authority is DownloadsProvider. + */ + public static boolean isDownloadsDocument(Uri uri) { + return "com.android.providers.downloads.documents".equals(uri.getAuthority()); + } + + /** + * @param uri The Uri to check. + * @return Whether the Uri authority is MediaProvider. + */ + public static boolean isMediaDocument(Uri uri) { + return "com.android.providers.media.documents".equals(uri.getAuthority()); + } + + /** + * @param uri The Uri to check. + * @return Whether the Uri authority is Google Photos. + */ + public static boolean isGooglePhotosUri(Uri uri) { + return "com.google.android.apps.photos.content".equals(uri.getAuthority()); + } + + /** + * + * @param uri The Uri to check. + * @return Whether the Uri authority is Google Drive. + */ + public static boolean isGoogleDriveDocument(Uri uri) { + return "com.google.android.apps.docs.storage".equals(uri.getAuthority()); + } + /** * Pushes a directory to the drop down list * @param directory to push From 903b66595f80fa2ff05b53797f27a7c072443b57 Mon Sep 17 00:00:00 2001 From: jabarros Date: Tue, 11 Nov 2014 12:27:57 +0100 Subject: [PATCH 03/16] Add workaround for Drive app in which a creation of a temporal copy is needed --- .../operations/UploadFileOperation.java | 118 +++++++++++------- .../ui/activity/FileDisplayActivity.java | 37 +++++- 2 files changed, 106 insertions(+), 49 deletions(-) diff --git a/src/com/owncloud/android/operations/UploadFileOperation.java b/src/com/owncloud/android/operations/UploadFileOperation.java index 43fcaa555a..819d218fbc 100644 --- a/src/com/owncloud/android/operations/UploadFileOperation.java +++ b/src/com/owncloud/android/operations/UploadFileOperation.java @@ -31,11 +31,16 @@ import java.util.concurrent.atomic.AtomicBoolean; import org.apache.commons.httpclient.methods.PutMethod; import org.apache.commons.httpclient.methods.RequestEntity; +import android.accounts.Account; +import android.content.Context; +import android.net.Uri; + +import com.owncloud.android.MainApp; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.files.services.FileUploader; -import com.owncloud.android.lib.common.network.ProgressiveDataTransferer; -import com.owncloud.android.lib.common.network.OnDatatransferProgressListener; import com.owncloud.android.lib.common.OwnCloudClient; +import com.owncloud.android.lib.common.network.OnDatatransferProgressListener; +import com.owncloud.android.lib.common.network.ProgressiveDataTransferer; import com.owncloud.android.lib.common.operations.OperationCancelledException; import com.owncloud.android.lib.common.operations.RemoteOperation; import com.owncloud.android.lib.common.operations.RemoteOperationResult; @@ -46,9 +51,6 @@ import com.owncloud.android.lib.resources.files.ExistenceCheckRemoteOperation; import com.owncloud.android.lib.resources.files.UploadRemoteFileOperation; import com.owncloud.android.utils.FileStorageUtils; -import android.accounts.Account; -import android.content.Context; - /** * Remote operation performing the upload of a file to an ownCloud server @@ -92,10 +94,9 @@ public class UploadFileOperation extends RemoteOperation { throw new IllegalArgumentException("Illegal NULL account in UploadFileOperation creation"); if (file == null) throw new IllegalArgumentException("Illegal NULL file in UploadFileOperation creation"); - if (file.getStoragePath() == null || file.getStoragePath().length() <= 0 - || !(new File(file.getStoragePath()).exists())) { + if (file.getStoragePath() == null || file.getStoragePath().length() <= 0) { throw new IllegalArgumentException( - "Illegal file in UploadFileOperation; storage path invalid or file not found: " + "Illegal file in UploadFileOperation; storage path invalid: " + file.getStoragePath()); } @@ -218,51 +219,75 @@ public class UploadFileOperation extends RemoteOperation { // copied } else { + String temporalPath = FileStorageUtils.getTemporalPath(mAccount.name) + mFile.getRemotePath(); mFile.setStoragePath(temporalPath); temporalFile = new File(temporalPath); - if (!mOriginalStoragePath.equals(temporalPath)) { // preventing - // weird - // but - // possible - // situation - InputStream in = null; - OutputStream out = null; - try { - File temporalParent = temporalFile.getParentFile(); - temporalParent.mkdirs(); - if (!temporalParent.isDirectory()) { - throw new IOException("Unexpected error: parent directory could not be created"); - } - temporalFile.createNewFile(); - if (!temporalFile.isFile()) { - throw new IOException("Unexpected error: target file could not be created"); - } - in = new FileInputStream(originalFile); + + File temporalParent = temporalFile.getParentFile(); + temporalParent.mkdirs(); + if (!temporalParent.isDirectory()) { + throw new IOException("Unexpected error: parent directory could not be created"); + } + temporalFile.createNewFile(); + if (!temporalFile.isFile()) { + throw new IOException("Unexpected error: target file could not be created"); + } + + InputStream in = null; + OutputStream out = null; + + try { + + if (mOriginalStoragePath.startsWith("content://")) { + + Uri uri = Uri.parse(mOriginalStoragePath); + + in = MainApp.getAppContext().getContentResolver().openInputStream(uri); out = new FileOutputStream(temporalFile); - byte[] buf = new byte[1024]; - int len; - while ((len = in.read(buf)) > 0) { - out.write(buf, 0, len); + + int nRead; + byte[] data = new byte[16384]; + + while ((nRead = in.read(data, 0, data.length)) != -1) { + out.write(data, 0, nRead); } + out.flush(); + + } else { + if (!mOriginalStoragePath.equals(temporalPath)) { // preventing + // weird + // but + // possible + // situation + + in = new FileInputStream(originalFile); + out = new FileOutputStream(temporalFile); + byte[] buf = new byte[1024]; + int len; + while ((len = in.read(buf)) > 0) { + out.write(buf, 0, len); + } + } + } + + } catch (Exception e) { + result = new RemoteOperationResult(ResultCode.LOCAL_STORAGE_NOT_COPIED); + return result; + + } finally { + try { + if (in != null) + in.close(); } catch (Exception e) { - result = new RemoteOperationResult(ResultCode.LOCAL_STORAGE_NOT_COPIED); - return result; - - } finally { - try { - if (in != null) - in.close(); - } catch (Exception e) { - Log_OC.d(TAG, "Weird exception while closing input stream for " + mOriginalStoragePath + " (ignoring)", e); - } - try { - if (out != null) - out.close(); - } catch (Exception e) { - Log_OC.d(TAG, "Weird exception while closing output stream for " + expectedPath + " (ignoring)", e); - } + Log_OC.d(TAG, "Weird exception while closing input stream for " + mOriginalStoragePath + " (ignoring)", e); + } + try { + if (out != null) + out.close(); + } catch (Exception e) { + Log_OC.d(TAG, "Weird exception while closing output stream for " + expectedPath + " (ignoring)", e); } } } @@ -417,5 +442,4 @@ public class UploadFileOperation extends RemoteOperation { public void cancel() { mUploadOperation.cancel(); } - } diff --git a/src/com/owncloud/android/ui/activity/FileDisplayActivity.java b/src/com/owncloud/android/ui/activity/FileDisplayActivity.java index ad6a072a86..bc0231fb1d 100644 --- a/src/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/src/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -49,9 +49,11 @@ import android.os.IBinder; import android.preference.PreferenceManager; import android.provider.DocumentsContract; import android.provider.MediaStore; +import android.provider.OpenableColumns; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentTransaction; +import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; @@ -691,7 +693,34 @@ OnSslUntrustedCertListener, OnEnforceableRefreshListener { } if (!remotepath.endsWith(OCFile.PATH_SEPARATOR)) remotepath += OCFile.PATH_SEPARATOR; - remotepath += new File(filepath).getName(); + + if (filepath.startsWith("content://")) { + // The query, since it only applies to a single document, will only return + // one row. There's no need to filter, sort, or select fields, since we want + // all fields for one document. + Cursor cursor = MainApp.getAppContext().getContentResolver() + .query(Uri.parse(filepath), null, null, null, null, null); + + try { + // moveToFirst() returns false if the cursor has 0 rows. Very handy for + // "if there's anything to look at, look at it" conditionals. + if (cursor != null && cursor.moveToFirst()) { + + // Note it's called "Display Name". This is + // provider-specific, and might not necessarily be the file name. + String displayName = cursor.getString( + cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)); + Log.i(TAG, "Display Name: " + displayName); + + remotepath += displayName; + } + } finally { + cursor.close(); + } + + } else { + remotepath += new File(filepath).getName(); + } i.putExtra(FileUploader.KEY_LOCAL_FILE, filepath); i.putExtra(FileUploader.KEY_REMOTE_FILE, remotepath); @@ -919,7 +948,11 @@ OnSslUntrustedCertListener, OnEnforceableRefreshListener { final String[] selectionArgs = new String[] { split[1] }; return getDataColumn(getApplicationContext(), contentUri, selection, selectionArgs); - } + } + // Google Drive + else if (isGoogleDriveDocument(uri)) { + return uri.toString(); + } } // MediaStore (and general) else if ("content".equalsIgnoreCase(uri.getScheme())) { From 3cae3d3eb84a0b734ee9ca8a27ee7df29232d90e Mon Sep 17 00:00:00 2001 From: jabarros Date: Wed, 12 Nov 2014 08:46:29 +0100 Subject: [PATCH 04/16] Modify kitkat document provider implementation in order to cover all 'content://' cases --- .../android/ui/activity/FileDisplayActivity.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/com/owncloud/android/ui/activity/FileDisplayActivity.java b/src/com/owncloud/android/ui/activity/FileDisplayActivity.java index bc0231fb1d..2469dcf714 100644 --- a/src/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/src/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -949,8 +949,8 @@ OnSslUntrustedCertListener, OnEnforceableRefreshListener { return getDataColumn(getApplicationContext(), contentUri, selection, selectionArgs); } - // Google Drive - else if (isGoogleDriveDocument(uri)) { + // Documents providers returned as content://... + else if (isAContentDocument(uri)) { return uri.toString(); } } @@ -1041,6 +1041,15 @@ OnSslUntrustedCertListener, OnEnforceableRefreshListener { return "com.google.android.apps.docs.storage".equals(uri.getAuthority()); } + /** + * + * @param uri The Uri to check. + * @return Whether the Uri is from a content provider as kind "content://..." + */ + public static boolean isAContentDocument(Uri uri) { + return uri.toString().startsWith("content://"); + } + /** * Pushes a directory to the drop down list * @param directory to push From e4d6f267f7373aeac535747cb05e48e6dfc7e166 Mon Sep 17 00:00:00 2001 From: jabarros Date: Wed, 12 Nov 2014 12:46:33 +0100 Subject: [PATCH 05/16] Create static var for defining 'content://' String into FileDisplayActivity and delete some unnecessary comments --- .../ui/activity/FileDisplayActivity.java | 29 +++++-------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/src/com/owncloud/android/ui/activity/FileDisplayActivity.java b/src/com/owncloud/android/ui/activity/FileDisplayActivity.java index 2469dcf714..c258498e07 100644 --- a/src/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/src/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -157,7 +157,9 @@ OnSslUntrustedCertListener, OnEnforceableRefreshListener { private String DIALOG_UNTRUSTED_CERT; private OCFile mWaitingToSend; - + + private static final String URI_TYPE_OF_CONTENT_PROVIDER = "content://"; + @Override protected void onCreate(Bundle savedInstanceState) { Log_OC.d(TAG, "onCreate() start"); @@ -694,20 +696,14 @@ OnSslUntrustedCertListener, OnEnforceableRefreshListener { if (!remotepath.endsWith(OCFile.PATH_SEPARATOR)) remotepath += OCFile.PATH_SEPARATOR; - if (filepath.startsWith("content://")) { + if (filepath.startsWith(URI_TYPE_OF_CONTENT_PROVIDER)) { // The query, since it only applies to a single document, will only return - // one row. There's no need to filter, sort, or select fields, since we want - // all fields for one document. + // one row. Cursor cursor = MainApp.getAppContext().getContentResolver() .query(Uri.parse(filepath), null, null, null, null, null); try { - // moveToFirst() returns false if the cursor has 0 rows. Very handy for - // "if there's anything to look at, look at it" conditionals. if (cursor != null && cursor.moveToFirst()) { - - // Note it's called "Display Name". This is - // provider-specific, and might not necessarily be the file name. String displayName = cursor.getString( cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)); Log.i(TAG, "Display Name: " + displayName); @@ -950,7 +946,7 @@ OnSslUntrustedCertListener, OnEnforceableRefreshListener { return getDataColumn(getApplicationContext(), contentUri, selection, selectionArgs); } // Documents providers returned as content://... - else if (isAContentDocument(uri)) { + else if (isContentDocument(uri)) { return uri.toString(); } } @@ -1031,23 +1027,14 @@ OnSslUntrustedCertListener, OnEnforceableRefreshListener { public static boolean isGooglePhotosUri(Uri uri) { return "com.google.android.apps.photos.content".equals(uri.getAuthority()); } - - /** - * - * @param uri The Uri to check. - * @return Whether the Uri authority is Google Drive. - */ - public static boolean isGoogleDriveDocument(Uri uri) { - return "com.google.android.apps.docs.storage".equals(uri.getAuthority()); - } /** * * @param uri The Uri to check. * @return Whether the Uri is from a content provider as kind "content://..." */ - public static boolean isAContentDocument(Uri uri) { - return uri.toString().startsWith("content://"); + public static boolean isContentDocument(Uri uri) { + return uri.toString().startsWith(URI_TYPE_OF_CONTENT_PROVIDER); } /** From 5d784d98b4b86e0d047ac2bdf5539495ccfb81f8 Mon Sep 17 00:00:00 2001 From: jabarros Date: Wed, 12 Nov 2014 16:07:37 +0100 Subject: [PATCH 06/16] Get file mimeType and pass it for being checked on UploadFileOperation class. Take into account if file extension comes in content Uri --- .../owncloud/android/datamodel/OCFile.java | 9 +++++ .../operations/UploadFileOperation.java | 24 +++++++++++- .../ui/activity/FileDisplayActivity.java | 38 +++++++++++++++---- 3 files changed, 62 insertions(+), 9 deletions(-) diff --git a/src/com/owncloud/android/datamodel/OCFile.java b/src/com/owncloud/android/datamodel/OCFile.java index 392d03bc88..70296d5fb0 100644 --- a/src/com/owncloud/android/datamodel/OCFile.java +++ b/src/com/owncloud/android/datamodel/OCFile.java @@ -156,6 +156,15 @@ public class OCFile implements Parcelable, Comparable { return mRemotePath; } + /** + * Can be used to set the path where the file will be stored + * + * @param remote_path to set + */ + public void setRemotePath(String remote_path) { + mRemotePath = remote_path; + } + /** * Can be used to check, whether or not this file exists in the database * already diff --git a/src/com/owncloud/android/operations/UploadFileOperation.java b/src/com/owncloud/android/operations/UploadFileOperation.java index 819d218fbc..f9590698a5 100644 --- a/src/com/owncloud/android/operations/UploadFileOperation.java +++ b/src/com/owncloud/android/operations/UploadFileOperation.java @@ -61,6 +61,10 @@ public class UploadFileOperation extends RemoteOperation { private static final String TAG = UploadFileOperation.class.getSimpleName(); + private static final String URI_CONTENT_SCHEME = "content://"; + private static final String MIME_TYPE_PDF = "application/pdf"; + private static final String FILE_EXTENSION_PDF = ".pdf"; + private Account mAccount; private OCFile mFile; private OCFile mOldFile; @@ -221,6 +225,12 @@ public class UploadFileOperation extends RemoteOperation { } else { String temporalPath = FileStorageUtils.getTemporalPath(mAccount.name) + mFile.getRemotePath(); + + if (isPdfFileFromContentProviderWithoutExtension()){ + temporalPath += FILE_EXTENSION_PDF; + mFile.setRemotePath(mFile.getRemotePath() + FILE_EXTENSION_PDF); + } + mFile.setStoragePath(temporalPath); temporalFile = new File(temporalPath); @@ -239,7 +249,8 @@ public class UploadFileOperation extends RemoteOperation { try { - if (mOriginalStoragePath.startsWith("content://")) { + // In case document provider schema as 'content://' + if (mOriginalStoragePath.startsWith(URI_CONTENT_SCHEME)) { Uri uri = Uri.parse(mOriginalStoragePath); @@ -442,4 +453,15 @@ public class UploadFileOperation extends RemoteOperation { public void cancel() { mUploadOperation.cancel(); } + + /** + * Checks if content provider, using the content:// scheme, returns a file with mime-type + * 'application/pdf' but file has not extension + * @return true if is needed to add the pdf file extension to the file + */ + private boolean isPdfFileFromContentProviderWithoutExtension() { + return mOriginalStoragePath.startsWith(URI_CONTENT_SCHEME) && + mFile.getMimetype().equals(MIME_TYPE_PDF) && + !mFile.getFileName().endsWith(FILE_EXTENSION_PDF); + } } diff --git a/src/com/owncloud/android/ui/activity/FileDisplayActivity.java b/src/com/owncloud/android/ui/activity/FileDisplayActivity.java index c258498e07..57656d6485 100644 --- a/src/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/src/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -158,7 +158,7 @@ OnSslUntrustedCertListener, OnEnforceableRefreshListener { private OCFile mWaitingToSend; - private static final String URI_TYPE_OF_CONTENT_PROVIDER = "content://"; + private static final String URI_CONTENT_SCHEME = "content://"; @Override protected void onCreate(Bundle savedInstanceState) { @@ -662,8 +662,12 @@ OnSslUntrustedCertListener, OnEnforceableRefreshListener { private void requestSimpleUpload(Intent data, int resultCode) { String filepath = null; + String mimeType = null; + + Uri selectedImageUri = data.getData(); + try { - Uri selectedImageUri = data.getData(); + mimeType = getContentResolver().getType(selectedImageUri); String filemanagerstring = selectedImageUri.getPath(); String selectedImagePath = getPath(selectedImageUri); @@ -696,9 +700,8 @@ OnSslUntrustedCertListener, OnEnforceableRefreshListener { if (!remotepath.endsWith(OCFile.PATH_SEPARATOR)) remotepath += OCFile.PATH_SEPARATOR; - if (filepath.startsWith(URI_TYPE_OF_CONTENT_PROVIDER)) { - // The query, since it only applies to a single document, will only return - // one row. + if (filepath.startsWith(URI_CONTENT_SCHEME)) { + Cursor cursor = MainApp.getAppContext().getContentResolver() .query(Uri.parse(filepath), null, null, null, null, null); @@ -706,9 +709,10 @@ OnSslUntrustedCertListener, OnEnforceableRefreshListener { if (cursor != null && cursor.moveToFirst()) { String displayName = cursor.getString( cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)); - Log.i(TAG, "Display Name: " + displayName); + Log.i(TAG, "Display Name: " + displayName + "; mimeType: " + mimeType); + + remotepath += displayName + getComposedFileExtension(filepath); - remotepath += displayName; } } finally { cursor.close(); @@ -720,6 +724,7 @@ OnSslUntrustedCertListener, OnEnforceableRefreshListener { i.putExtra(FileUploader.KEY_LOCAL_FILE, filepath); i.putExtra(FileUploader.KEY_REMOTE_FILE, remotepath); + i.putExtra(FileUploader.KEY_MIME_TYPE, mimeType); i.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_SINGLE_FILE); if (resultCode == UploadFilesActivity.RESULT_OK_AND_MOVE) i.putExtra(FileUploader.KEY_LOCAL_BEHAVIOUR, FileUploader.LOCAL_BEHAVIOUR_MOVE); @@ -1034,7 +1039,7 @@ OnSslUntrustedCertListener, OnEnforceableRefreshListener { * @return Whether the Uri is from a content provider as kind "content://..." */ public static boolean isContentDocument(Uri uri) { - return uri.toString().startsWith(URI_TYPE_OF_CONTENT_PROVIDER); + return uri.toString().startsWith(URI_CONTENT_SCHEME); } /** @@ -1946,4 +1951,21 @@ OnSslUntrustedCertListener, OnEnforceableRefreshListener { private void sortByName(boolean ascending){ getListOfFilesFragment().sortByName(ascending); } + + /** + * Get the file extension if it is on path as type "content://.../DocInfo.doc" + * @param filepath: Content Uri converted to string format + * @return String: fileExtension (type '.pdf'). Empty if no extension + */ + private String getComposedFileExtension(String filepath) { + String fileExtension = ""; + String fileNameInContentUri = filepath.substring(filepath.lastIndexOf("/")); + + // Check if extension is included in uri + int pos = fileNameInContentUri.lastIndexOf('.'); + if (pos >= 0) { + fileExtension = fileNameInContentUri.substring(pos); + } + return fileExtension; + } } From e398ad0c633f665f7166545b7f2e90730e871349 Mon Sep 17 00:00:00 2001 From: Oliver Gasser Date: Fri, 14 Nov 2014 00:55:53 +0100 Subject: [PATCH 07/16] Convert IDN from ASCII to Unicode in Upload Dialog Display IDN host names as Unicode in the FileUpload Dialog. This dialog is shown when multiple ownCloud accounts are setup and a file is shared with ownCloud. Fixes #708. --- src/com/owncloud/android/ui/activity/Uploader.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/owncloud/android/ui/activity/Uploader.java b/src/com/owncloud/android/ui/activity/Uploader.java index 66359f3d6d..6c8a1320be 100644 --- a/src/com/owncloud/android/ui/activity/Uploader.java +++ b/src/com/owncloud/android/ui/activity/Uploader.java @@ -170,7 +170,7 @@ public class Uploader extends SherlockListActivity implements OnItemClickListene case DIALOG_MULTIPLE_ACCOUNT: CharSequence ac[] = new CharSequence[mAccountManager.getAccountsByType(MainApp.getAccountType()).length]; for (int i = 0; i < ac.length; ++i) { - ac[i] = mAccountManager.getAccountsByType(MainApp.getAccountType())[i].name; + ac[i] = DisplayUtils.convertIdn(mAccountManager.getAccountsByType(MainApp.getAccountType())[i].name, false); } builder.setTitle(R.string.common_choose_account); builder.setItems(ac, new OnClickListener() { From 297cb6b5c336a58a5a527da314154e4d3acf078b Mon Sep 17 00:00:00 2001 From: jabarros Date: Mon, 17 Nov 2014 11:32:46 +0100 Subject: [PATCH 08/16] Refactoring to avoid maintenance after CR --- .../owncloud/android/datamodel/OCFile.java | 9 -- .../android/files/services/FileUploader.java | 48 ++++++-- .../operations/UploadFileOperation.java | 24 +--- .../ui/activity/FileDisplayActivity.java | 111 ++---------------- .../owncloud/android/utils/DisplayUtils.java | 17 +++ src/com/owncloud/android/utils/UriUtils.java | 103 ++++++++++++++++ 6 files changed, 169 insertions(+), 143 deletions(-) create mode 100644 src/com/owncloud/android/utils/UriUtils.java diff --git a/src/com/owncloud/android/datamodel/OCFile.java b/src/com/owncloud/android/datamodel/OCFile.java index 70296d5fb0..392d03bc88 100644 --- a/src/com/owncloud/android/datamodel/OCFile.java +++ b/src/com/owncloud/android/datamodel/OCFile.java @@ -156,15 +156,6 @@ public class OCFile implements Parcelable, Comparable { return mRemotePath; } - /** - * Can be used to set the path where the file will be stored - * - * @param remote_path to set - */ - public void setRemotePath(String remote_path) { - mRemotePath = remote_path; - } - /** * Can be used to check, whether or not this file exists in the database * already diff --git a/src/com/owncloud/android/files/services/FileUploader.java b/src/com/owncloud/android/files/services/FileUploader.java index ad2a2cbe44..0480440242 100644 --- a/src/com/owncloud/android/files/services/FileUploader.java +++ b/src/com/owncloud/android/files/services/FileUploader.java @@ -73,6 +73,7 @@ import com.owncloud.android.operations.common.SyncOperation; import com.owncloud.android.ui.activity.FileActivity; import com.owncloud.android.ui.activity.FileDisplayActivity; import com.owncloud.android.utils.ErrorMessageAdapter; +import com.owncloud.android.utils.UriUtils; @@ -120,6 +121,9 @@ public class FileUploader extends Service implements OnDatatransferProgressListe private NotificationCompat.Builder mNotificationBuilder; private int mLastPercent; + private static final String MIME_TYPE_PDF = "application/pdf"; + private static final String FILE_EXTENSION_PDF = ".pdf"; + public static String getUploadFinishMessage() { return FileUploader.class.getName().toString() + UPLOAD_FINISH_MESSAGE; @@ -646,18 +650,6 @@ public class FileUploader extends Service implements OnDatatransferProgressListe private OCFile obtainNewOCFileToUpload(String remotePath, String localPath, String mimeType, FileDataStorageManager storageManager) { - OCFile newFile = new OCFile(remotePath); - newFile.setStoragePath(localPath); - newFile.setLastSyncDateForProperties(0); - newFile.setLastSyncDateForData(0); - - // size - if (localPath != null && localPath.length() > 0) { - File localFile = new File(localPath); - newFile.setFileLength(localFile.length()); - newFile.setLastSyncDateForData(localFile.lastModified()); - } // don't worry about not assigning size, the problems with localPath - // are checked when the UploadFileOperation instance is created // MIME type if (mimeType == null || mimeType.length() <= 0) { @@ -671,6 +663,25 @@ public class FileUploader extends Service implements OnDatatransferProgressListe if (mimeType == null) { mimeType = "application/octet-stream"; } + + if (isPdfFileFromContentProviderWithoutExtension(localPath, mimeType)){ + remotePath += FILE_EXTENSION_PDF; + } + + OCFile newFile = new OCFile(remotePath); + newFile.setStoragePath(localPath); + newFile.setLastSyncDateForProperties(0); + newFile.setLastSyncDateForData(0); + + // size + if (localPath != null && localPath.length() > 0) { + File localFile = new File(localPath); + newFile.setFileLength(localFile.length()); + newFile.setLastSyncDateForData(localFile.lastModified()); + } // don't worry about not assigning size, the problems with localPath + // are checked when the UploadFileOperation instance is created + + newFile.setMimetype(mimeType); return newFile; @@ -856,4 +867,17 @@ public class FileUploader extends Service implements OnDatatransferProgressListe sendStickyBroadcast(end); } + /** + * Checks if content provider, using the content:// scheme, returns a file with mime-type + * 'application/pdf' but file has not extension + * @param localPath + * @param mimeType + * @return true if is needed to add the pdf file extension to the file + */ + private boolean isPdfFileFromContentProviderWithoutExtension(String localPath, String mimeType) { + return localPath.startsWith(UriUtils.URI_CONTENT_SCHEME) && + mimeType.equals(MIME_TYPE_PDF) && + !localPath.endsWith(FILE_EXTENSION_PDF); + } + } diff --git a/src/com/owncloud/android/operations/UploadFileOperation.java b/src/com/owncloud/android/operations/UploadFileOperation.java index f9590698a5..1536a604f7 100644 --- a/src/com/owncloud/android/operations/UploadFileOperation.java +++ b/src/com/owncloud/android/operations/UploadFileOperation.java @@ -50,6 +50,7 @@ import com.owncloud.android.lib.resources.files.ChunkedUploadRemoteFileOperation import com.owncloud.android.lib.resources.files.ExistenceCheckRemoteOperation; import com.owncloud.android.lib.resources.files.UploadRemoteFileOperation; import com.owncloud.android.utils.FileStorageUtils; +import com.owncloud.android.utils.UriUtils; /** @@ -61,10 +62,6 @@ public class UploadFileOperation extends RemoteOperation { private static final String TAG = UploadFileOperation.class.getSimpleName(); - private static final String URI_CONTENT_SCHEME = "content://"; - private static final String MIME_TYPE_PDF = "application/pdf"; - private static final String FILE_EXTENSION_PDF = ".pdf"; - private Account mAccount; private OCFile mFile; private OCFile mOldFile; @@ -225,12 +222,6 @@ public class UploadFileOperation extends RemoteOperation { } else { String temporalPath = FileStorageUtils.getTemporalPath(mAccount.name) + mFile.getRemotePath(); - - if (isPdfFileFromContentProviderWithoutExtension()){ - temporalPath += FILE_EXTENSION_PDF; - mFile.setRemotePath(mFile.getRemotePath() + FILE_EXTENSION_PDF); - } - mFile.setStoragePath(temporalPath); temporalFile = new File(temporalPath); @@ -250,7 +241,7 @@ public class UploadFileOperation extends RemoteOperation { try { // In case document provider schema as 'content://' - if (mOriginalStoragePath.startsWith(URI_CONTENT_SCHEME)) { + if (mOriginalStoragePath.startsWith(UriUtils.URI_CONTENT_SCHEME)) { Uri uri = Uri.parse(mOriginalStoragePath); @@ -453,15 +444,4 @@ public class UploadFileOperation extends RemoteOperation { public void cancel() { mUploadOperation.cancel(); } - - /** - * Checks if content provider, using the content:// scheme, returns a file with mime-type - * 'application/pdf' but file has not extension - * @return true if is needed to add the pdf file extension to the file - */ - private boolean isPdfFileFromContentProviderWithoutExtension() { - return mOriginalStoragePath.startsWith(URI_CONTENT_SCHEME) && - mFile.getMimetype().equals(MIME_TYPE_PDF) && - !mFile.getFileName().endsWith(FILE_EXTENSION_PDF); - } } diff --git a/src/com/owncloud/android/ui/activity/FileDisplayActivity.java b/src/com/owncloud/android/ui/activity/FileDisplayActivity.java index 57656d6485..ec2e9be4ac 100644 --- a/src/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/src/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -107,6 +107,7 @@ import com.owncloud.android.ui.preview.PreviewMediaFragment; import com.owncloud.android.ui.preview.PreviewVideoActivity; import com.owncloud.android.utils.DisplayUtils; import com.owncloud.android.utils.ErrorMessageAdapter; +import com.owncloud.android.utils.UriUtils; /** @@ -158,8 +159,6 @@ OnSslUntrustedCertListener, OnEnforceableRefreshListener { private OCFile mWaitingToSend; - private static final String URI_CONTENT_SCHEME = "content://"; - @Override protected void onCreate(Bundle savedInstanceState) { Log_OC.d(TAG, "onCreate() start"); @@ -700,7 +699,7 @@ OnSslUntrustedCertListener, OnEnforceableRefreshListener { if (!remotepath.endsWith(OCFile.PATH_SEPARATOR)) remotepath += OCFile.PATH_SEPARATOR; - if (filepath.startsWith(URI_CONTENT_SCHEME)) { + if (filepath.startsWith(UriUtils.URI_CONTENT_SCHEME)) { Cursor cursor = MainApp.getAppContext().getContentResolver() .query(Uri.parse(filepath), null, null, null, null, null); @@ -711,7 +710,7 @@ OnSslUntrustedCertListener, OnEnforceableRefreshListener { cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)); Log.i(TAG, "Display Name: " + displayName + "; mimeType: " + mimeType); - remotepath += displayName + getComposedFileExtension(filepath); + remotepath += displayName + DisplayUtils.getComposedFileExtension(filepath); } } finally { @@ -912,7 +911,7 @@ OnSslUntrustedCertListener, OnEnforceableRefreshListener { // DocumentProvider if (isKitKat && DocumentsContract.isDocumentUri(getApplicationContext(), uri)) { // ExternalStorageProvider - if (isExternalStorageDocument(uri)) { + if (UriUtils.isExternalStorageDocument(uri)) { final String docId = DocumentsContract.getDocumentId(uri); final String[] split = docId.split(":"); final String type = split[0]; @@ -922,16 +921,16 @@ OnSslUntrustedCertListener, OnEnforceableRefreshListener { } } // DownloadsProvider - else if (isDownloadsDocument(uri)) { + else if (UriUtils.isDownloadsDocument(uri)) { final String id = DocumentsContract.getDocumentId(uri); final Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(id)); - return getDataColumn(getApplicationContext(), contentUri, null, null); + return UriUtils.getDataColumn(getApplicationContext(), contentUri, null, null); } // MediaProvider - else if (isMediaDocument(uri)) { + else if (UriUtils.isMediaDocument(uri)) { final String docId = DocumentsContract.getDocumentId(uri); final String[] split = docId.split(":"); final String type = split[0]; @@ -948,10 +947,10 @@ OnSslUntrustedCertListener, OnEnforceableRefreshListener { final String selection = "_id=?"; final String[] selectionArgs = new String[] { split[1] }; - return getDataColumn(getApplicationContext(), contentUri, selection, selectionArgs); + return UriUtils.getDataColumn(getApplicationContext(), contentUri, selection, selectionArgs); } // Documents providers returned as content://... - else if (isContentDocument(uri)) { + else if (UriUtils.isContentDocument(uri)) { return uri.toString(); } } @@ -959,10 +958,10 @@ OnSslUntrustedCertListener, OnEnforceableRefreshListener { else if ("content".equalsIgnoreCase(uri.getScheme())) { // Return the remote address - if (isGooglePhotosUri(uri)) + if (UriUtils.isGooglePhotosUri(uri)) return uri.getLastPathSegment(); - return getDataColumn(getApplicationContext(), uri, null, null); + return UriUtils.getDataColumn(getApplicationContext(), uri, null, null); } // File else if ("file".equalsIgnoreCase(uri.getScheme())) { @@ -971,77 +970,6 @@ OnSslUntrustedCertListener, OnEnforceableRefreshListener { return null; } - /** - * Get the value of the data column for this Uri. This is useful for - * MediaStore Uris, and other file-based ContentProviders. - * - * @param context The context. - * @param uri The Uri to query. - * @param selection (Optional) Filter used in the query. - * @param selectionArgs (Optional) Selection arguments used in the query. - * @return The value of the _data column, which is typically a file path. - */ - public static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) { - - Cursor cursor = null; - final String column = "_data"; - final String[] projection = { column }; - - try { - cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null); - if (cursor != null && cursor.moveToFirst()) { - - final int column_index = cursor.getColumnIndexOrThrow(column); - return cursor.getString(column_index); - } - } finally { - if (cursor != null) - cursor.close(); - } - return null; - } - - /** - * @param uri The Uri to check. - * @return Whether the Uri authority is ExternalStorageProvider. - */ - public static boolean isExternalStorageDocument(Uri uri) { - return "com.android.externalstorage.documents".equals(uri.getAuthority()); - } - - /** - * @param uri The Uri to check. - * @return Whether the Uri authority is DownloadsProvider. - */ - public static boolean isDownloadsDocument(Uri uri) { - return "com.android.providers.downloads.documents".equals(uri.getAuthority()); - } - - /** - * @param uri The Uri to check. - * @return Whether the Uri authority is MediaProvider. - */ - public static boolean isMediaDocument(Uri uri) { - return "com.android.providers.media.documents".equals(uri.getAuthority()); - } - - /** - * @param uri The Uri to check. - * @return Whether the Uri authority is Google Photos. - */ - public static boolean isGooglePhotosUri(Uri uri) { - return "com.google.android.apps.photos.content".equals(uri.getAuthority()); - } - - /** - * - * @param uri The Uri to check. - * @return Whether the Uri is from a content provider as kind "content://..." - */ - public static boolean isContentDocument(Uri uri) { - return uri.toString().startsWith(URI_CONTENT_SCHEME); - } - /** * Pushes a directory to the drop down list * @param directory to push @@ -1951,21 +1879,4 @@ OnSslUntrustedCertListener, OnEnforceableRefreshListener { private void sortByName(boolean ascending){ getListOfFilesFragment().sortByName(ascending); } - - /** - * Get the file extension if it is on path as type "content://.../DocInfo.doc" - * @param filepath: Content Uri converted to string format - * @return String: fileExtension (type '.pdf'). Empty if no extension - */ - private String getComposedFileExtension(String filepath) { - String fileExtension = ""; - String fileNameInContentUri = filepath.substring(filepath.lastIndexOf("/")); - - // Check if extension is included in uri - int pos = fileNameInContentUri.lastIndexOf('.'); - if (pos >= 0) { - fileExtension = fileNameInContentUri.substring(pos); - } - return fileExtension; - } } diff --git a/src/com/owncloud/android/utils/DisplayUtils.java b/src/com/owncloud/android/utils/DisplayUtils.java index 804a4dd061..f8e1accb7c 100644 --- a/src/com/owncloud/android/utils/DisplayUtils.java +++ b/src/com/owncloud/android/utils/DisplayUtils.java @@ -274,4 +274,21 @@ public class DisplayUtils { return url; } } + + /** + * Get the file extension if it is on path as type "content://.../DocInfo.doc" + * @param filepath: Content Uri converted to string format + * @return String: fileExtension (type '.pdf'). Empty if no extension + */ + public static String getComposedFileExtension(String filepath) { + String fileExtension = ""; + String fileNameInContentUri = filepath.substring(filepath.lastIndexOf("/")); + + // Check if extension is included in uri + int pos = fileNameInContentUri.lastIndexOf('.'); + if (pos >= 0) { + fileExtension = fileNameInContentUri.substring(pos); + } + return fileExtension; + } } diff --git a/src/com/owncloud/android/utils/UriUtils.java b/src/com/owncloud/android/utils/UriUtils.java new file mode 100644 index 0000000000..e66d2c9f25 --- /dev/null +++ b/src/com/owncloud/android/utils/UriUtils.java @@ -0,0 +1,103 @@ +/* ownCloud Android client application + * Copyright (C) 2012-2014 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 . + * + */ + +package com.owncloud.android.utils; + +import android.content.Context; +import android.database.Cursor; +import android.net.Uri; + + +/** + * A helper class for some Uri operations. + */ +public class UriUtils { + + public static final String URI_CONTENT_SCHEME = "content://"; + + + /** + * Get the value of the data column for this Uri. This is useful for + * MediaStore Uris, and other file-based ContentProviders. + * + * @param context The context. + * @param uri The Uri to query. + * @param selection (Optional) Filter used in the query. + * @param selectionArgs (Optional) Selection arguments used in the query. + * @return The value of the _data column, which is typically a file path. + */ + public static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) { + + Cursor cursor = null; + final String column = "_data"; + final String[] projection = { column }; + + try { + cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null); + if (cursor != null && cursor.moveToFirst()) { + + final int column_index = cursor.getColumnIndexOrThrow(column); + return cursor.getString(column_index); + } + } finally { + if (cursor != null) + cursor.close(); + } + return null; + } + + /** + * @param uri The Uri to check. + * @return Whether the Uri authority is ExternalStorageProvider. + */ + public static boolean isExternalStorageDocument(Uri uri) { + return "com.android.externalstorage.documents".equals(uri.getAuthority()); + } + + /** + * @param uri The Uri to check. + * @return Whether the Uri authority is DownloadsProvider. + */ + public static boolean isDownloadsDocument(Uri uri) { + return "com.android.providers.downloads.documents".equals(uri.getAuthority()); + } + + /** + * @param uri The Uri to check. + * @return Whether the Uri authority is MediaProvider. + */ + public static boolean isMediaDocument(Uri uri) { + return "com.android.providers.media.documents".equals(uri.getAuthority()); + } + + /** + * @param uri The Uri to check. + * @return Whether the Uri authority is Google Photos. + */ + public static boolean isGooglePhotosUri(Uri uri) { + return "com.google.android.apps.photos.content".equals(uri.getAuthority()); + } + + /** + * + * @param uri The Uri to check. + * @return Whether the Uri is from a content provider as kind "content://..." + */ + public static boolean isContentDocument(Uri uri) { + return uri.toString().startsWith(URI_CONTENT_SCHEME); + } +} From 05cb87c172ebd89d4dcc3e090a955ec5a4266fe4 Mon Sep 17 00:00:00 2001 From: jabarros Date: Mon, 17 Nov 2014 13:51:04 +0100 Subject: [PATCH 09/16] Update library reference --- owncloud-android-library | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/owncloud-android-library b/owncloud-android-library index 5bd0d73877..4f315c7e06 160000 --- a/owncloud-android-library +++ b/owncloud-android-library @@ -1 +1 @@ -Subproject commit 5bd0d7387712ce3f53869294761ac4d8537841cd +Subproject commit 4f315c7e06f6eef48df246be0ee9252fdfccdf00 From 6224f73544405ed645dd00d136ad167e4c235876 Mon Sep 17 00:00:00 2001 From: jabarros Date: Mon, 17 Nov 2014 14:07:48 +0100 Subject: [PATCH 10/16] Fix crash in Android Lollipop when cliking on refresh the whole account --- .../owncloud/android/ui/activity/FileDisplayActivity.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/com/owncloud/android/ui/activity/FileDisplayActivity.java b/src/com/owncloud/android/ui/activity/FileDisplayActivity.java index b5d543a4e2..998d8b851d 100644 --- a/src/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/src/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -563,6 +563,11 @@ OnSslUntrustedCertListener, OnEnforceableRefreshListener { builder.setExpedited(true); builder.setManual(true); builder.syncOnce(); + + // Fix bug in Android Lollipop when you click on refresh the whole account + Bundle extras = new Bundle(); + builder.setExtras(extras); + SyncRequest request = builder.build(); ContentResolver.requestSync(request); } From 4d04e70d122dbdd95923d37eaec9f7f0a066b112 Mon Sep 17 00:00:00 2001 From: "David A. Velasco" Date: Mon, 17 Nov 2014 15:18:22 +0100 Subject: [PATCH 11/16] Update reference to library after upgrading TLS support --- owncloud-android-library | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/owncloud-android-library b/owncloud-android-library index 5bd0d73877..2799b3e853 160000 --- a/owncloud-android-library +++ b/owncloud-android-library @@ -1 +1 @@ -Subproject commit 5bd0d7387712ce3f53869294761ac4d8537841cd +Subproject commit 2799b3e853c79e8ebb37051c92dfcc43f8d63788 From d3bfbb856805d4c988fcfed85d760ba511658da9 Mon Sep 17 00:00:00 2001 From: Jenkins for ownCloud Date: Tue, 18 Nov 2014 01:13:34 -0500 Subject: [PATCH 12/16] [tx-robot] updated from transifex --- res/values-fr/strings.xml | 82 +++++++++++++++++++-------------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml index b882f466dc..3656d14f9a 100644 --- a/res/values-fr/strings.xml +++ b/res/values-fr/strings.xml @@ -40,18 +40,18 @@ Empreinte Mémoriser l\'emplacement de partage Mémoriser le dernier emplacement d\'upload - Essayez %1$s sur votre smartphone ! - J\'aimerais vous inviter à utiliser %1$s sur votre smartphone ! -Téléchargez-le ici : %2$s + Essayez %1$s sur votre smartphone&nbsp;! + J'aimerais vous inviter à utiliser %1$s sur votre smartphone ! +Téléchargez-le ici&nbsp;: %2$s Vérifier le serveur - Adresse du serveur https://... + Adresse du serveur https://… Nom d\'utilisateur Mot de passe - Nouveau dans %1$s ? + Nouveau dans %1$s&nbsp;? Fichiers Connecter Téléverser - Sélectionner le dossier d\'envoi : + Sélectionner le dossier d'envoi&nbsp;: Aucun compte n\'a été trouvé Aucun compte %1$s n\'a été trouvé. Veuillez commencer par en configurer un. Paramètres @@ -61,7 +61,7 @@ Téléchargez-le ici : %2$s %1$s n\'est pas autorisé à accéder au contenu partagé Téléversement il y a quelques secondes - Il n\'y a rien ici ! Envoyez donc quelque chose :) + Il n'y a rien ici&nbsp;! Envoyez donc quelque chose :) Chargement… Aucun fichier n\'est présent dans ce dossier. Effleurez un fichier pour afficher les informations complémentaires @@ -82,8 +82,8 @@ Téléchargez-le ici : %2$s Annuler Sauvegarder & Quitter Erreur - Chargement ... - Erreur Inconnue + Chargement… + Erreur inconnue À propos de Changer de mot de passe Effacer ce compte @@ -113,7 +113,7 @@ Téléchargez-le ici : %2$s Des conflits ont été trouvés %1$d fichiers à garder synchronisés n\'ont put être synchronisé La synchronisation des fichiers a échoué - Le contenu de %1$d fichiers n\'a put être synchronisé (%2$d conflits) + Le contenu de %1$d fichiers n\'a pu être synchronisé (%2$d conflits) Certains fichiers locaux ont été oubliés %1$d fichiers du dossier %2$s n\'ont pas pu être copiés dans Depuis la version 1.3.16, les fichiers envoyé depuis ce périphérique sont copiés dans le dossier local %1$s pour éviter une perte de données lorsqu\'un même fichier est synchronisé avec plusieurs comptes. @@ -125,7 +125,7 @@ Ci-dessous la liste des fichiers locaux, et les fichiers distants dans %5$s auxq Tout déplacer Tous les fichiers ont été déplacés Certains fichiers n\'ont pu être déplacés - Local: %1$s + Local&nbsp;: %1$s Distant : %1$s Il n\'y a pas assez de place disponible pour copier les fichiers sélectionnés dans le dossier %1$s. Voulez-vous quand même les déplacer ? Veuillez saisir votre code de sécurité @@ -149,15 +149,15 @@ Ci-dessous la liste des fichiers locaux, et les fichiers distants dans %5$s auxq Le fichier média n\'est pas correctement encodé Délai dépassé pour la lecture du morceau. Le fichier média ne peut pas être diffusé - Fichier média ne peut être joué avec le stock de media player + Le fichier média ne peut être joué avec le lecteur standard Erreur de sécurité à la lecture de %1$s Erreur de lecture de fichier à la lecture de %1$s Erreur inattendue à la lecture de %1$s - Bouton de rem-bobinage - Bouton de Lecture ou de Pause + Bouton de rembobinage + Bouton de lecture ou de pause Bouton d\'avance rapide - Demande d\'autorisation... - Tentative de connexion … + Demande d\'autorisation… + Tentative de connexion… Pas de connexion réseau Connexion sécurisée non disponible Connexion établie @@ -171,18 +171,18 @@ Ci-dessous la liste des fichiers locaux, et les fichiers distants dans %5$s auxq Le serveur met trop longtemps à répondre Adresse invalide Échec de l\'initialisation SSL - Impossible de vérifier l\'identité du serveur SSL. + Impossible de vérifier l\'identité du serveur SSL La version du serveur n\'est pas reconnue Impossible d\'établir la connexion Connexion sécurisée établie Nom d\'utilisateur ou mot de passe incorrect Échec d\'autorisation Accès refusé par le serveur d\'autorisation - État inattendu ; veuillez entrer à nouveau l\'URL du serveur + État inattendu&nbsp;; veuillez entrer à nouveau l'URL du serveur Votre autorisation a expiré. Merci de vous authentifier à nouveau Veuillez saisir le mot de passe courant Votre session a expiré. Merci de vous reconnecter - Connexion au serveur d\'authentification... + Connexion au serveur d\'authentification… Le serveur ne prend pas en charge pas cette méthode d\'authentification %1$s ne prend pas en charge les comptes multiples Votre serveur a retourné un identifiant d\'utilisateur incorrect. Veuillez prendre contact avec votre administrateur @@ -191,8 +191,8 @@ Ci-dessous la liste des fichiers locaux, et les fichiers distants dans %5$s auxq Maintenir le fichier à jour Renommer Supprimer - Voulez-vous vraiment supprimer %1$s ? - Voulez-vous vraiment supprimer %1$s et son contenu ? + Voulez-vous vraiment supprimer %1$s&nbsp;? + Voulez-vous vraiment supprimer %1$s et son contenu&nbsp;? Local seulement Le contenu local uniquement Effacer du serveur @@ -205,36 +205,36 @@ Ci-dessous la liste des fichiers locaux, et les fichiers distants dans %5$s auxq Le fichier distant n\'a pu être vérifié Le contenu des fichiers est déjà synchronisé Le dossier n\'a pas pu être créé - Caractères interdits : / \\ < > : \" | ? * + Caractères interdits&nbsp;: / \\ &lt; &gt; : " | ? * Le nom du fichier ne peut pas être vide Veuillez patienter - Problème inattendu. Veuillez essayer une autre app pour la sélection du fichier + Problème inattendu. Veuillez essayer une autre application pour la sélection du fichier Aucun fichier sélectionné Envoyer un lien à… - Connexion avec aAuth2. - Connexion au serveur aAuth2... + Connexion avec oAuth2 + Connexion au serveur oAuth2… L\'identité du site ne peut être vérifiée - Le certificat du serveur n\'est pas sûr - Le certificat du serveur a expiré - Le certificat du serveur n\'est pas encore valide - L\'URL ne correspond pas au nom d\'hôte du certificat - Voulez-vous tout de même faire confiance à ce certificat ? + Voulez-vous tout de même faire confiance à ce certificat&nbsp;? Impossible de sauvegarder le certificat Détails Masquer - Délivré à : - Délivré par : - Nom d\'usage : - Organisation : - Unité organisationnelle : - Pays : - Région : - Localisation : - Validité : - De : - À : - Signature : - Algorithme : + Délivré à&nbsp;: + Délivré par&nbsp;: + Nom d'usage&nbsp;: + Organisation&nbsp;: + Unité organisationnelle&nbsp;: + Pays&nbsp;: + Région&nbsp;: + Localisation&nbsp;: + Validité&nbsp;: + De&nbsp;: + À&nbsp;: + Signature&nbsp;: + Algorithme&nbsp;: Impossible d\'afficher le certificat. - Aucune information sur l\'erreur Ceci est un espace réservé @@ -255,7 +255,7 @@ Ci-dessous la liste des fichiers locaux, et les fichiers distants dans %5$s auxq Cette image ne peut pas être affichée %1$s n\'a pas pu être copié dans le dossier local %2$s Chemin d\'accès pour le téléversement - Désolé, le partage n\'est pas disponible sur votre serveur. Contactez votre administrateur, s\'il vous plait. + Désolé, le partage n\'est pas disponible sur votre serveur. Veuillez contacter votre administrateur. Impossible de partager. Vérifiez que le fichier est bien présent Une erreur est survenue lors de la tentative de partage de ce fichier ou répertoire Impossible de supprimer le partage. Vérifiez que le fichier est bien présent @@ -263,7 +263,7 @@ Ci-dessous la liste des fichiers locaux, et les fichiers distants dans %5$s auxq Envoyer Copier le lien Copié dans le presse-papiers - Erreur critique : impossible de réaliser des opérations + Erreur critique&nbsp;: impossible de réaliser des opérations Une erreur s\'est produite pendant la connection au serveur Une erreur est survenue pendant l\'attente du serveur. L\'opération n\'a pas pu être effectuée. Une erreur est survenue pendant l\'attente du serveur. L\'opération n\'a pas pu être effectuée. From 387374bed215873c283965b963a3ef7d0cc4b5ba Mon Sep 17 00:00:00 2001 From: jabarros Date: Tue, 18 Nov 2014 10:35:52 +0100 Subject: [PATCH 13/16] Fix errors in Frechn translations and reaname var in FileDisplayActivity --- res/values-fr/strings.xml | 10 +++++----- .../android/ui/activity/FileDisplayActivity.java | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml index 3656d14f9a..2cf16ac9e4 100644 --- a/res/values-fr/strings.xml +++ b/res/values-fr/strings.xml @@ -41,7 +41,7 @@ Mémoriser l\'emplacement de partage Mémoriser le dernier emplacement d\'upload Essayez %1$s sur votre smartphone&nbsp;! - J'aimerais vous inviter à utiliser %1$s sur votre smartphone ! + J\'aimerais vous inviter à utiliser %1$s sur votre smartphone ! Téléchargez-le ici&nbsp;: %2$s Vérifier le serveur Adresse du serveur https://… @@ -51,7 +51,7 @@ Téléchargez-le ici&nbsp;: %2$s Fichiers Connecter Téléverser - Sélectionner le dossier d'envoi&nbsp;: + Sélectionner le dossier d\'envoi&nbsp;: Aucun compte n\'a été trouvé Aucun compte %1$s n\'a été trouvé. Veuillez commencer par en configurer un. Paramètres @@ -61,7 +61,7 @@ Téléchargez-le ici&nbsp;: %2$s %1$s n\'est pas autorisé à accéder au contenu partagé Téléversement il y a quelques secondes - Il n'y a rien ici&nbsp;! Envoyez donc quelque chose :) + Il n\'y a rien ici&nbsp;! Envoyez donc quelque chose :) Chargement… Aucun fichier n\'est présent dans ce dossier. Effleurez un fichier pour afficher les informations complémentaires @@ -178,7 +178,7 @@ Ci-dessous la liste des fichiers locaux, et les fichiers distants dans %5$s auxq Nom d\'utilisateur ou mot de passe incorrect Échec d\'autorisation Accès refusé par le serveur d\'autorisation - État inattendu&nbsp;; veuillez entrer à nouveau l'URL du serveur + État inattendu&nbsp;; veuillez entrer à nouveau l\'URL du serveur Votre autorisation a expiré. Merci de vous authentifier à nouveau Veuillez saisir le mot de passe courant Votre session a expiré. Merci de vous reconnecter @@ -224,7 +224,7 @@ Ci-dessous la liste des fichiers locaux, et les fichiers distants dans %5$s auxq Masquer Délivré à&nbsp;: Délivré par&nbsp;: - Nom d'usage&nbsp;: + Nom d\'usage&nbsp;: Organisation&nbsp;: Unité organisationnelle&nbsp;: Pays&nbsp;: diff --git a/src/com/owncloud/android/ui/activity/FileDisplayActivity.java b/src/com/owncloud/android/ui/activity/FileDisplayActivity.java index ec2e9be4ac..c3332eb31f 100644 --- a/src/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/src/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -906,10 +906,10 @@ OnSslUntrustedCertListener, OnEnforceableRefreshListener { * @return The path to the content or null if it could not be found */ public String getPath(Uri uri) { - final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT; + final boolean isKitKatOrLater = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT; // DocumentProvider - if (isKitKat && DocumentsContract.isDocumentUri(getApplicationContext(), uri)) { + if (isKitKatOrLater && DocumentsContract.isDocumentUri(getApplicationContext(), uri)) { // ExternalStorageProvider if (UriUtils.isExternalStorageDocument(uri)) { final String docId = DocumentsContract.getDocumentId(uri); From bb8a10f735ac9ef9c1173b279e5aee68a0f8fd73 Mon Sep 17 00:00:00 2001 From: Jenkins for ownCloud Date: Wed, 19 Nov 2014 01:13:30 -0500 Subject: [PATCH 14/16] [tx-robot] updated from transifex --- res/values-fr/strings.xml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml index 3656d14f9a..90c7ba74da 100644 --- a/res/values-fr/strings.xml +++ b/res/values-fr/strings.xml @@ -41,8 +41,8 @@ Mémoriser l\'emplacement de partage Mémoriser le dernier emplacement d\'upload Essayez %1$s sur votre smartphone&nbsp;! - J'aimerais vous inviter à utiliser %1$s sur votre smartphone ! -Téléchargez-le ici&nbsp;: %2$s + J\'aimerais vous inviter à utiliser %1$s sur votre smartphone ! +Téléchargez-le ici : %2$s Vérifier le serveur Adresse du serveur https://… Nom d\'utilisateur @@ -51,7 +51,7 @@ Téléchargez-le ici&nbsp;: %2$s Fichiers Connecter Téléverser - Sélectionner le dossier d'envoi&nbsp;: + Sélectionner le dossier d\'envoi : Aucun compte n\'a été trouvé Aucun compte %1$s n\'a été trouvé. Veuillez commencer par en configurer un. Paramètres @@ -61,7 +61,7 @@ Téléchargez-le ici&nbsp;: %2$s %1$s n\'est pas autorisé à accéder au contenu partagé Téléversement il y a quelques secondes - Il n'y a rien ici&nbsp;! Envoyez donc quelque chose :) + Il n\'y a rien ici ! Envoyez donc quelque chose :) Chargement… Aucun fichier n\'est présent dans ce dossier. Effleurez un fichier pour afficher les informations complémentaires @@ -178,7 +178,7 @@ Ci-dessous la liste des fichiers locaux, et les fichiers distants dans %5$s auxq Nom d\'utilisateur ou mot de passe incorrect Échec d\'autorisation Accès refusé par le serveur d\'autorisation - État inattendu&nbsp;; veuillez entrer à nouveau l'URL du serveur + État inattendu ; veuillez entrer à nouveau l\'URL du serveur Votre autorisation a expiré. Merci de vous authentifier à nouveau Veuillez saisir le mot de passe courant Votre session a expiré. Merci de vous reconnecter @@ -224,7 +224,7 @@ Ci-dessous la liste des fichiers locaux, et les fichiers distants dans %5$s auxq Masquer Délivré à&nbsp;: Délivré par&nbsp;: - Nom d'usage&nbsp;: + Nom d\'usage : Organisation&nbsp;: Unité organisationnelle&nbsp;: Pays&nbsp;: From 703366c45970d051609fe5758948a5103f6e931c Mon Sep 17 00:00:00 2001 From: "David A. Velasco" Date: Wed, 19 Nov 2014 11:05:32 +0100 Subject: [PATCH 15/16] Fix failed uploads when display name of file brough from external apps includes separator or path-separator characters --- src/com/owncloud/android/ui/activity/FileDisplayActivity.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/com/owncloud/android/ui/activity/FileDisplayActivity.java b/src/com/owncloud/android/ui/activity/FileDisplayActivity.java index c3332eb31f..d78fdc0337 100644 --- a/src/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/src/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -710,6 +710,8 @@ OnSslUntrustedCertListener, OnEnforceableRefreshListener { cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)); Log.i(TAG, "Display Name: " + displayName + "; mimeType: " + mimeType); + displayName.replace(File.separatorChar, '_'); + displayName.replace(File.pathSeparatorChar, '_'); remotepath += displayName + DisplayUtils.getComposedFileExtension(filepath); } From ddfe992cbff314c367bcf6ecf82c2fd5bdd4edeb Mon Sep 17 00:00:00 2001 From: Jenkins for ownCloud Date: Thu, 20 Nov 2014 01:13:29 -0500 Subject: [PATCH 16/16] [tx-robot] updated from transifex --- res/values-pt-rPT/strings.xml | 62 +++++++++++++++++------------------ 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml index 4da13ba2be..072a085089 100644 --- a/res/values-pt-rPT/strings.xml +++ b/res/values-pt-rPT/strings.xml @@ -1,6 +1,6 @@ - %1$s Aplicação(ões) Android + %1$s App(s) Android versão %1$s Atualizar conta Enviar @@ -51,15 +51,15 @@ Ligar Enviar Escolha a pasta de envio: - Nenhuma conta encontrada - Não tem nenhuma conta %1$s no seu dispositivo. Configure uma conta. + A conta não foi encontrada + Não tem nenhuma conta %1$s no seu dispositivo. Por favor, configure primeiro uma conta. Configurar Sair - Sem conteúdo para carregar + Sem conteúdo para enviar Não foi recebido nenhum conteúdo. Nada para enviar. O %1$s não está autorizado a aceder aos ficheiro partilhados. A enviar - Minutos atrás + segundos atrás Vazio. Envie alguma coisa! A carregar ... Não existem ficheiros nesta pasta. @@ -215,12 +215,12 @@ Quer confiar neste certificado de qualquer maneira? O certificado não pôde ser guardado Detalhes - Esconder + Ocultar Emitido para: Emitido por: Nome comum. Organização: - Unidade organizaconal. + Unidade organizacional. País: Estado: Localização: @@ -229,33 +229,33 @@ Para: Assinatura: Algoritmo - O certificado não pôde ser mostrado. - - Nenhuma informação acerca do erro + Não foi possível mostrar o certificado. + - Nenhuma informação sobre o erro Isto é uma variável. placeholder.txt Imagem PNG 389 KB - 2012/05/18 12:23 PM + 2012/05/18 12:23 12:23:45 - Enviar fotografias apenas via WiFi - Enviar videos apenas por WiFi - /Upload-Instantâneo - Conflito na actualização + Só enviar as fotografias via wi-fi + Só enviar os vídeos por wi-fi + /Envio Instantâneo + Conflito na atualização O ficheiro remoto %s não está sincronizado com o ficheiro local. Se continuar ira substituir o ficheiro no servidor. - Manter os dois - Sobrepor + Manter ambos + Substituir Não enviar. - Pré-Visualização da imagem + Pré-Visualizar imagem Esta imagem não pode ser mostrada Não foi possível copiar %1$s para a pasta local %2$s - Caminho de Upload + Caminho de \'A Enviar\' Lamentamos mas não é possível partilhar através do seu servidor. Por favor contacte o seu administrador. Não é possivel partilhar. Por favor verifique se o ficheiro existe Ocorreu um erro enquanto tentava partilhar este ficheiro ou pasta Não é possível retirar a partilha. Verifique se o ficheiro existe Ocorreu um erro enquanto retirava a partilha deste ficheiro ou pasta Enviar - Copiar ligação + Copiar hiperligação Copiado para a área de transferência Erro crítico: não é possível executar as operações Ocorreu um erro durante a ligação ao servidos. @@ -263,31 +263,31 @@ Ocorreu um erro durante a ligação ao servidor, não foi possível realizar a operação. A operação não foi concluída, o servidor está inacessível. - Você não tem permissão %s + Não tem permissão %s para renomear este ficheiro - para eliminar este ficheiro + para apagar este ficheiro para partilhar este ficheiro - para eliminar a partilha deste ficheiro + para cancelar a partilha deste ficheiro para criar o ficheiro - para carregar dentro desta pasta + para enviar nesta pasta O ficheiro não está mais disponível no servidor Contas Adicionar conta Ligação segura é redireccionada para um caminho inseguro. - Logs + Registos de Alterações Enviar Histórico - Logs da app ownCloud Android - A carregar os dados... + Registos das alterações da app ownCloud Android + A carregar os dados ... Autenticação necessária - Password errada + Palavra-passe errada Mover Não está aqui nada. Pode adicionar uma pasta! - Escolha - Não é possível mover. Verifique se o ficheiro existe + Escolher + Não é possível mover. Por favor, verifique se o ficheiro existe Não é possível mover esta pasta deste modo O ficheiro já existe na pasta de destino - Um erro ocorreu ao tentar mover este ficheiro ou pasta + Ocorreu um ocorreu quando tentava mover este ficheiro ou pasta para mover este ficheiro - Uploads Instantâneos + Envios Instantâneos Segurança