From: Jorge Antonio Diaz-Benito Soriano Date: Mon, 24 Nov 2014 11:57:02 +0000 (+0100) Subject: Merge branch 'gradleWithInternalDependency' into us4_view_text_files X-Git-Tag: oc-android-1.8~17^2~8^2~9 X-Git-Url: http://git.linex4red.de/pub/Android/ownCloud.git/commitdiff_plain/10a12fb96085121482a500c55cd4784cd8970088?hp=da2702129f6deefb66310ebe2da2ef73e664682d Merge branch 'gradleWithInternalDependency' into us4_view_text_files Conflicts: src/com/owncloud/android/ui/activity/FileDisplayActivity.java --- diff --git a/.gitignore b/.gitignore index a218d0b9..e13e5a5e 100644 --- a/.gitignore +++ b/.gitignore @@ -11,7 +11,6 @@ # generated files bin/ build/ -*.iml gen/ target/ @@ -32,10 +31,14 @@ oc_framework/proguard-project.txt oc_framework-test-project/proguard-project.txt tests/proguard-project.txt -# Android Studio and Gradle specific entries +# IntelliJ and Gradle specific entries .gradle -.idea -*.iml +.idea/workspace.xml +.idea/tasks.xml +.idea/libraries/*.xml +dataSources.ids +datasources.xml +gradle.xml build # Actionbarsherlock is now ignored since scripts takes care of init the sub-modules. diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 00000000..1fd74d19 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +android \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 00000000..217af471 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,23 @@ + + + + + + diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 00000000..e7bedf33 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 00000000..e206d70d --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 00000000..cded4964 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 00000000..0ca17d19 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 00000000..922003b8 --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 00000000..275077f8 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/SETUP.md b/SETUP.md index a9e2a93b..cfbd2418 100644 --- a/SETUP.md +++ b/SETUP.md @@ -86,9 +86,8 @@ NOTE: Even though API level is set to 19, APK also runs on older devices because * Complete the setup of project properties running: - Windows: "setup_env.bat gradle" - Mac OS/Linux: "./setup_env.sh gradle" -* The first time you want to open the project in Android Studio, select 'Import Project...' and choose the file "android/settings.gradle". - Android Studio will then create the '.iml' files it needs. If you ever close the project but the files are still there, you just select - 'Open Project...'. The file chooser will show an Android face as the folder icon, which you can select to reopen the project. +* Select 'Open Project...'. The file chooser will show an Android face as the folder icon. Select + it to open the project. * To build the project, follow the guidelines shown on [4. Building with Gradle][2]. ### 7. Create pull request: diff --git a/android.iml b/android.iml new file mode 100644 index 00000000..50ce0aa2 --- /dev/null +++ b/android.iml @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/owncloud-android-library b/owncloud-android-library index 99f8c869..005dd85f 160000 --- a/owncloud-android-library +++ b/owncloud-android-library @@ -1 +1 @@ -Subproject commit 99f8c869702a3261d9868207968700277e208507 +Subproject commit 005dd85fdc475c6af0b981a91c758fc41123cf25 diff --git a/res/menu/file_select_all.xml b/res/menu/file_select_all.xml deleted file mode 100644 index a8097aae..00000000 --- a/res/menu/file_select_all.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml index b882f466..90c7ba74 100644 --- a/res/values-fr/strings.xml +++ b/res/values-fr/strings.xml @@ -40,14 +40,14 @@ Empreinte Mémoriser l\'emplacement de partage Mémoriser le dernier emplacement d\'upload - Essayez %1$s sur votre smartphone ! + Essayez %1$s sur votre smartphone&nbsp;! 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://... + Adresse du serveur https://… Nom d\'utilisateur Mot de passe - Nouveau dans %1$s ? + Nouveau dans %1$s&nbsp;? Fichiers Connecter Téléverser @@ -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,7 +171,7 @@ 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 @@ -182,7 +182,7 @@ Ci-dessous la liste des fichiers locaux, et les fichiers distants dans %5$s auxq 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 : + Délivré à&nbsp;: + Délivré par&nbsp;: Nom d\'usage : - Organisation : - Unité organisationnelle : - Pays : - Région : - Localisation : - Validité : - De : - À : - Signature : - Algorithme : + 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. diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml index 4da13ba2..072a0850 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 diff --git a/src/com/owncloud/android/files/services/FileUploader.java b/src/com/owncloud/android/files/services/FileUploader.java index ad2a2cbe..04804402 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 43fcaa55..1536a604 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; @@ -45,9 +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 android.accounts.Account; -import android.content.Context; +import com.owncloud.android.utils.UriUtils; /** @@ -92,10 +95,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,52 +220,77 @@ 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 { + + // In case document provider schema as 'content://' + if (mOriginalStoragePath.startsWith(UriUtils.URI_CONTENT_SCHEME)) { + + 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); - } - } 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); + int nRead; + byte[] data = new byte[16384]; + + while ((nRead = in.read(data, 0, data.length)) != -1) { + out.write(data, 0, nRead); } - try { - if (out != null) - out.close(); - } catch (Exception e) { - Log_OC.d(TAG, "Weird exception while closing output stream for " + expectedPath + " (ignoring)", e); + + 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) { + 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 +444,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 627d40cf..20507ea5 100644 --- a/src/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/src/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -28,6 +28,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; @@ -38,13 +39,18 @@ 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.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; @@ -99,6 +105,7 @@ import com.owncloud.android.ui.preview.PreviewTextFragment; 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; import java.io.File; import java.io.IOException; @@ -569,6 +576,11 @@ public class FileDisplayActivity extends HookActivity implements 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); } @@ -660,8 +672,12 @@ public class FileDisplayActivity extends HookActivity implements 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); @@ -693,10 +709,34 @@ public class FileDisplayActivity extends HookActivity implements } if (!remotepath.endsWith(OCFile.PATH_SEPARATOR)) remotepath += OCFile.PATH_SEPARATOR; - remotepath += new File(filepath).getName(); + + if (filepath.startsWith(UriUtils.URI_CONTENT_SCHEME)) { + + Cursor cursor = MainApp.getAppContext().getContentResolver() + .query(Uri.parse(filepath), null, null, null, null, null); + + try { + if (cursor != null && cursor.moveToFirst()) { + String displayName = cursor.getString( + 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); + + } + } finally { + cursor.close(); + } + + } else { + remotepath += new File(filepath).getName(); + } 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); @@ -873,22 +913,74 @@ public class FileDisplayActivity extends HookActivity implements return dialog; } - /** * Translates a content URI of an image 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 isKitKatOrLater = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT; + + // DocumentProvider + if (isKitKatOrLater && DocumentsContract.isDocumentUri(getApplicationContext(), uri)) { + // ExternalStorageProvider + if (UriUtils.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 (UriUtils.isDownloadsDocument(uri)) { + + final String id = DocumentsContract.getDocumentId(uri); + final Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), + Long.valueOf(id)); + + return UriUtils.getDataColumn(getApplicationContext(), contentUri, null, null); + } + // MediaProvider + else if (UriUtils.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 UriUtils.getDataColumn(getApplicationContext(), contentUri, selection, selectionArgs); + } + // Documents providers returned as content://... + else if (UriUtils.isContentDocument(uri)) { + return uri.toString(); + } + } + // MediaStore (and general) + else if ("content".equalsIgnoreCase(uri.getScheme())) { + + // Return the remote address + if (UriUtils.isGooglePhotosUri(uri)) + return uri.getLastPathSegment(); + + return UriUtils.getDataColumn(getApplicationContext(), uri, null, null); + } + // File + else if ("file".equalsIgnoreCase(uri.getScheme())) { + return uri.getPath(); } return null; } diff --git a/src/com/owncloud/android/ui/activity/UploadFilesActivity.java b/src/com/owncloud/android/ui/activity/UploadFilesActivity.java index 83e7bc07..09185726 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/activity/Uploader.java b/src/com/owncloud/android/ui/activity/Uploader.java index 66359f3d..6c8a1320 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() { diff --git a/src/com/owncloud/android/ui/fragment/LocalFileListFragment.java b/src/com/owncloud/android/ui/fragment/LocalFileListFragment.java index 62b41a3e..c9408b1e 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/src/com/owncloud/android/utils/DisplayUtils.java b/src/com/owncloud/android/utils/DisplayUtils.java index d8bf88f3..da81f539 100644 --- a/src/com/owncloud/android/utils/DisplayUtils.java +++ b/src/com/owncloud/android/utils/DisplayUtils.java @@ -277,7 +277,24 @@ 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; + } + public static CharSequence getRelativeDateTimeString(Context c, long time, long minResolution, long transitionResolution, int flags){ CharSequence dateString = ""; @@ -301,6 +318,6 @@ public class DisplayUtils { } } - return dateString.toString().split(",")[0]; + return dateString.toString().split(",")[0]; } } diff --git a/src/com/owncloud/android/utils/UriUtils.java b/src/com/owncloud/android/utils/UriUtils.java new file mode 100644 index 00000000..e66d2c9f --- /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); + } +} diff --git a/tests/.classpath b/tests/.classpath index 26d8fe48..9b141f6f 100644 --- a/tests/.classpath +++ b/tests/.classpath @@ -1,10 +1,10 @@ + + - -