android/app/build.gradle | 7 android/app/src/main/java/org/libreoffice/androidapp/storage/DocumentProviderFactory.java | 5 android/app/src/main/java/org/libreoffice/androidapp/storage/owncloud/OwnCloudFile.java | 178 +++++++++ android/app/src/main/java/org/libreoffice/androidapp/storage/owncloud/OwnCloudProvider.java | 192 ++++++++++ android/app/src/main/java/org/libreoffice/androidapp/ui/LibreOfficeUIActivity.java | 3 android/app/src/main/res/values/strings.xml | 4 6 files changed, 384 insertions(+), 5 deletions(-)
New commits: commit 8ff2ac2142498a600506927154fb6b513e55e3a7 Author: kaishu-sahu <kaishusahu...@gmail.com> AuthorDate: Tue Apr 2 00:51:06 2019 +0530 Commit: Jan Holesovsky <ke...@collabora.com> CommitDate: Mon Apr 8 18:45:30 2019 +0200 android: add ownCloud support from old app. Change-Id: I11f38bc7b35d2c7d9cc8a718232eac2efe13388f Reviewed-on: https://gerrit.libreoffice.org/70084 Reviewed-by: Jan Holesovsky <ke...@collabora.com> Tested-by: Jan Holesovsky <ke...@collabora.com> diff --git a/android/app/build.gradle b/android/app/build.gradle index fca7f39fe..522ff61b9 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -50,12 +50,19 @@ android { } } +repositories { + flatDir { + dirs "${liboWorkdir}/UnpackedTarball/owncloud_android_lib/build/outputs/aar" + } +} + dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'androidx.appcompat:appcompat:1.0.2' implementation 'androidx.constraintlayout:constraintlayout:1.1.3' implementation 'androidx.recyclerview:recyclerview:1.0.0' implementation 'com.google.android.material:material:1.1.0-alpha04' + implementation(name:'owncloud_android_lib', ext:'aar') } task copyUnpackAssets(type: Copy) { diff --git a/android/app/src/main/java/org/libreoffice/androidapp/storage/DocumentProviderFactory.java b/android/app/src/main/java/org/libreoffice/androidapp/storage/DocumentProviderFactory.java index 2fc3e031a..eb4a0ac91 100644 --- a/android/app/src/main/java/org/libreoffice/androidapp/storage/DocumentProviderFactory.java +++ b/android/app/src/main/java/org/libreoffice/androidapp/storage/DocumentProviderFactory.java @@ -16,12 +16,11 @@ import org.libreoffice.androidapp.storage.external.ExtsdDocumentsProvider; import org.libreoffice.androidapp.storage.external.OTGDocumentsProvider; import org.libreoffice.androidapp.storage.local.LocalDocumentsDirectoryProvider; import org.libreoffice.androidapp.storage.local.LocalDocumentsProvider; +import org.libreoffice.androidapp.storage.owncloud.OwnCloudProvider; import java.util.HashSet; import java.util.Set; -//import org.libreoffice.androidapp.storage.owncloud.OwnCloudProvider; - /** * Keeps the instances of the available IDocumentProviders in the system. * Instances are maintained in a sorted list and providers have to be @@ -64,7 +63,7 @@ public final class DocumentProviderFactory { instance.providers[0] = new LocalDocumentsDirectoryProvider(0); instance.providers[1] = new LocalDocumentsProvider(1); instance.providers[OTG_PROVIDER_INDEX] = new OTGDocumentsProvider(OTG_PROVIDER_INDEX, context); -// instance.providers[4] = new OwnCloudProvider(4, context); + instance.providers[4] = new OwnCloudProvider(4, context); instance.providers[EXTSD_PROVIDER_INDEX] = new ExtsdDocumentsProvider(EXTSD_PROVIDER_INDEX, context); diff --git a/android/app/src/main/java/org/libreoffice/androidapp/storage/owncloud/OwnCloudFile.java b/android/app/src/main/java/org/libreoffice/androidapp/storage/owncloud/OwnCloudFile.java new file mode 100644 index 000000000..21d800234 --- /dev/null +++ b/android/app/src/main/java/org/libreoffice/androidapp/storage/owncloud/OwnCloudFile.java @@ -0,0 +1,178 @@ +package org.libreoffice.androidapp.storage.owncloud; + +import android.content.Context; + +import java.io.File; +import java.io.FileFilter; +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import org.libreoffice.androidapp.storage.IFile; + +import com.owncloud.android.lib.common.operations.RemoteOperationResult; +import com.owncloud.android.lib.resources.files.ChunkedUploadRemoteFileOperation; +import com.owncloud.android.lib.resources.files.DownloadRemoteFileOperation; +import com.owncloud.android.lib.resources.files.ReadRemoteFolderOperation; +import com.owncloud.android.lib.resources.files.RemoteFile; +import com.owncloud.android.lib.resources.files.UploadRemoteFileOperation; + +/** + * Implementation of IFile for ownCloud servers. + */ +public class OwnCloudFile implements IFile { + + private OwnCloudProvider provider; + private RemoteFile file; + + private String name; + private String parentPath; + + protected OwnCloudFile(OwnCloudProvider provider, RemoteFile file) { + this.provider = provider; + this.file = file; + + // get name and parent from path + File localFile = new File(file.getRemotePath()); + this.name = localFile.getName(); + this.parentPath = localFile.getParent(); + } + + @Override + public URI getUri(){ + + try{ + return URI.create(URLEncoder.encode(file.getRemotePath(),"UTF-8")); + }catch(UnsupportedEncodingException e){ + e.printStackTrace(); + } + + return null; + } + + @Override + public String getName() { + return name; + } + + @Override + public boolean isDirectory() { + return file.getMimeType().equals("DIR"); + } + + @Override + public long getSize() { + return file.getLength(); + } + + @Override + public Date getLastModified() { + return new Date(file.getModifiedTimestamp()); + } + + @Override + public List<IFile> listFiles() { + List<IFile> children = new ArrayList<IFile>(); + if (isDirectory()) { + ReadRemoteFolderOperation refreshOperation = new ReadRemoteFolderOperation( + file.getRemotePath()); + RemoteOperationResult result = refreshOperation.execute(provider + .getClient()); + if (!result.isSuccess()) { + throw provider.buildRuntimeExceptionForResultCode(result.getCode()); + } + for (Object obj : result.getData()) { + RemoteFile child = (RemoteFile) obj; + if (!child.getRemotePath().equals(file.getRemotePath())) + children.add(new OwnCloudFile(provider, child)); + } + } + return children; + } + + @Override + public List<IFile> listFiles(FileFilter filter) { + List<IFile> children = new ArrayList<IFile>(); + if (isDirectory()) { + ReadRemoteFolderOperation refreshOperation = new ReadRemoteFolderOperation( + file.getRemotePath()); + RemoteOperationResult result = refreshOperation.execute(provider + .getClient()); + if (!result.isSuccess()) { + throw provider.buildRuntimeExceptionForResultCode(result.getCode()); + } + + for (Object obj : result.getData()) { + RemoteFile child = (RemoteFile) obj; + if (!child.getRemotePath().equals(file.getRemotePath())){ + OwnCloudFile ownCloudFile = new OwnCloudFile(provider, child); + if(!ownCloudFile.isDirectory()){ + File f = new File(provider.getCacheDir().getAbsolutePath(), + ownCloudFile.getName()); + if(filter.accept(f)) + children.add(ownCloudFile); + f.delete(); + }else{ + children.add(ownCloudFile); + } + } + } + } + return children; + } + + @Override + public IFile getParent(Context context) { + if (parentPath == null) + // this is the root node + return null; + + return provider.createFromUri(context, URI.create(parentPath)); + } + + @Override + public File getDocument() { + if (isDirectory()) { + return null; + } + File downFolder = provider.getCacheDir(); + DownloadRemoteFileOperation operation = new DownloadRemoteFileOperation( + file.getRemotePath(), downFolder.getAbsolutePath()); + RemoteOperationResult result = operation.execute(provider.getClient()); + if (!result.isSuccess()) { + throw provider.buildRuntimeExceptionForResultCode(result.getCode()); + } + return new File(downFolder.getAbsolutePath() + file.getRemotePath()); + } + + @Override + public boolean equals(Object object) { + if (this == object) + return true; + if (!(object instanceof OwnCloudFile)) + return false; + OwnCloudFile file = (OwnCloudFile) object; + return file.getUri().equals(getUri()); + } + + @Override + public void saveDocument(File newFile) { + UploadRemoteFileOperation uploadOperation; + if (newFile.length() > ChunkedUploadRemoteFileOperation.CHUNK_SIZE) { + uploadOperation = new ChunkedUploadRemoteFileOperation( + newFile.getPath(), file.getRemotePath(), file.getMimeType()); + } else { + uploadOperation = new UploadRemoteFileOperation(newFile.getPath(), + file.getRemotePath(), file.getMimeType()); + } + + RemoteOperationResult result = uploadOperation.execute(provider + .getClient()); + if (!result.isSuccess()) { + throw provider.buildRuntimeExceptionForResultCode(result.getCode()); + } + } +} diff --git a/android/app/src/main/java/org/libreoffice/androidapp/storage/owncloud/OwnCloudProvider.java b/android/app/src/main/java/org/libreoffice/androidapp/storage/owncloud/OwnCloudProvider.java new file mode 100644 index 000000000..e270c728c --- /dev/null +++ b/android/app/src/main/java/org/libreoffice/androidapp/storage/owncloud/OwnCloudProvider.java @@ -0,0 +1,192 @@ +package org.libreoffice.androidapp.storage.owncloud; + +import java.io.File; +import java.net.URI; + +import org.libreoffice.androidapp.R; +import org.libreoffice.androidapp.storage.DocumentProviderSettingsActivity; +import org.libreoffice.androidapp.storage.IDocumentProvider; +import org.libreoffice.androidapp.storage.IFile; + +import android.content.Context; +import android.content.SharedPreferences; +import android.content.SharedPreferences.OnSharedPreferenceChangeListener; +import android.net.Uri; +import android.preference.PreferenceManager; + +import com.owncloud.android.lib.common.OwnCloudClient; +import com.owncloud.android.lib.common.OwnCloudClientFactory; +import com.owncloud.android.lib.common.OwnCloudCredentialsFactory; +import com.owncloud.android.lib.common.operations.RemoteOperationResult; +import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode; +import com.owncloud.android.lib.resources.files.FileUtils; +import com.owncloud.android.lib.resources.files.ReadRemoteFileOperation; +import com.owncloud.android.lib.resources.files.RemoteFile; + + +/** + * Implementation of IDocumentProvider for ownCloud servers. + */ +public class OwnCloudProvider implements IDocumentProvider, + OnSharedPreferenceChangeListener { + + private int id; + + private Context context; + private OwnCloudClient client; + private File cacheDir; + + private String serverUrl; + private String userName; + private String password; + private RemoteOperationResult result; + + public OwnCloudProvider(int id, Context context) { + this.id = id; + this.context = context; + + // read preferences + SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context); + serverUrl = preferences.getString( + DocumentProviderSettingsActivity.KEY_PREF_OWNCLOUD_SERVER, ""); + userName = preferences.getString( + DocumentProviderSettingsActivity.KEY_PREF_OWNCLOUD_USER_NAME, ""); + password = preferences.getString( + DocumentProviderSettingsActivity.KEY_PREF_OWNCLOUD_PASSWORD, ""); + + setupClient(); + + // make sure cache directory exists, and clear it + // TODO: probably we should do smarter cache management + cacheDir = new File(context.getCacheDir(), "ownCloud"); + if (cacheDir.exists()) { + deleteRecursive(cacheDir); + } + cacheDir.mkdirs(); + } + + private void setupClient() { + Uri serverUri = Uri.parse(serverUrl); + client = OwnCloudClientFactory.createOwnCloudClient(serverUri, context, + true); + client.setCredentials(OwnCloudCredentialsFactory.newBasicCredentials( + userName, password)); + } + + @Override + public IFile getRootDirectory(Context context) { + return createFromUri(context, URI.create(FileUtils.PATH_SEPARATOR)); + } + + @Override + public IFile createFromUri(Context context, URI uri) { + if(serverUrl != "" || userName != "" || password != ""){ + ReadRemoteFileOperation refreshOperation = new ReadRemoteFileOperation( + uri.getPath()); + this.result = refreshOperation.execute(client); + if (!result.isSuccess()) { + throw buildRuntimeExceptionForResultCode(result.getCode()); + } + if (result.getData().size() > 0) { + return new OwnCloudFile(this, (RemoteFile) result.getData().get(0)); + } + } else { + throw buildRuntimeExceptionForResultCode(ResultCode.WRONG_CONNECTION); + } + + return null; + } + + @Override + public int getNameResource() { + return R.string.owncloud; + } + + /** + * Used by OwnCloudFiles to get a configured client to run their own + * operations. + * + * @return configured OwnCloudClient. + */ + protected OwnCloudClient getClient() { + return client; + } + + /** + * Used by OwnCloudFiles to get the cache directory they should download + * files to. + * + * @return cache directory. + */ + protected File getCacheDir() { + return cacheDir; + } + + /** + * Build the proper RuntimeException for some error result. + * + * @param code Result code got from some RemoteOperationResult. + * @return exception with the proper internationalized error message. + */ + protected RuntimeException buildRuntimeExceptionForResultCode(ResultCode code) { + int errorMessage; + switch (code) { + case WRONG_CONNECTION: // SocketException + case FILE_NOT_FOUND: // HTTP 404 + errorMessage = R.string.owncloud_wrong_connection; + break; + case UNAUTHORIZED: // wrong user/pass + errorMessage = R.string.owncloud_unauthorized; + break; + default: + errorMessage = R.string.owncloud_unspecified_error; + break; + } + return new RuntimeException(context.getString(errorMessage)); + } + + /** + * Deletes files and recursively deletes directories. + * + * @param file + * File or directory to be deleted. + */ + private static void deleteRecursive(File file) { + if (file.isDirectory()) { + for (File child : file.listFiles()) + deleteRecursive(child); + } + file.delete(); + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences preferences, + String key) { + boolean changed = false; + if (key.equals(DocumentProviderSettingsActivity.KEY_PREF_OWNCLOUD_SERVER)) { + serverUrl = preferences.getString(key, ""); + changed = true; + } + else if (key.equals(DocumentProviderSettingsActivity.KEY_PREF_OWNCLOUD_USER_NAME)) { + userName = preferences.getString(key, ""); + changed = true; + } + else if (key.equals(DocumentProviderSettingsActivity.KEY_PREF_OWNCLOUD_PASSWORD)) { + password = preferences.getString(key, ""); + changed = true; + } + + if (changed) + setupClient(); + } + + @Override + public int getId() { + return id; + } + + @Override + public boolean checkProviderAvailability(Context context) { + return client != null; + } +} diff --git a/android/app/src/main/java/org/libreoffice/androidapp/ui/LibreOfficeUIActivity.java b/android/app/src/main/java/org/libreoffice/androidapp/ui/LibreOfficeUIActivity.java index 7035fd473..8f003b6c0 100644 --- a/android/app/src/main/java/org/libreoffice/androidapp/ui/LibreOfficeUIActivity.java +++ b/android/app/src/main/java/org/libreoffice/androidapp/ui/LibreOfficeUIActivity.java @@ -261,8 +261,7 @@ public class LibreOfficeUIActivity extends AppCompatActivity implements /*Settin ); // Loop through the document providers menu items and check if they are available or not - //TODO remove -1. Used right now to ignore opencloud - for (int index = 0; index < providerNames.size() - 1; index++) { + for (int index = 0; index < providerNames.size(); index++) { MenuItem item = navigationDrawer.getMenu().getItem(index); item.setEnabled(documentProviderFactory.getProvider(index).checkProviderAvailability(this)); } diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml index bfde02318..69f49d340 100644 --- a/android/app/src/main/res/values/strings.xml +++ b/android/app/src/main/res/values/strings.xml @@ -55,6 +55,10 @@ <string name="owncloud">Remote server</string> <string name="usb_connected_configure">USB connected, configure your device.</string> + <string name="owncloud_wrong_connection">Cannot connect to ownCloud server. Check your configuration.</string> + <string name="owncloud_unauthorized">Cannot log into ownCloud server. Check your configuration.</string> + <string name="owncloud_unspecified_error">Unspecified error connecting to ownCloud server. Check your configuration and/or try later.</string> + <string name="ext_document_provider_error">Invalid root file. Check your sd card configuration.</string> <string name="otg_missing_error">Invalid root file. Check your OTG device and/or configuration.</string> _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits