diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index eb352ad22c5..7ad2cfa6615 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -129,17 +129,29 @@
android:name=".providers.FileContentProvider"
android:authorities="@string/authority"
android:enabled="true"
- android:exported="false"
+ android:exported="true"
android:label="@string/sync_string_files"
android:syncable="true" />
+
+
+
+
+
+
+
+
+ true
+
\ No newline at end of file
diff --git a/res/values/bools.xml b/res/values/bools.xml
index c2ca6732c83..e070bbcfc07 100644
--- a/res/values/bools.xml
+++ b/res/values/bools.xml
@@ -19,4 +19,5 @@
false
+ false
\ No newline at end of file
diff --git a/res/values/setup.xml b/res/values/setup.xml
index 02127007563..02334f9b379 100644
--- a/res/values/setup.xml
+++ b/res/values/setup.xml
@@ -4,6 +4,7 @@
ownCloud
owncloud
org.owncloud
+ org.owncloud.documents
owncloud.db
ownCloud
owncloud
diff --git a/src/com/owncloud/android/authentication/AccountUtils.java b/src/com/owncloud/android/authentication/AccountUtils.java
index 7bf180213c8..28a6ecd894e 100644
--- a/src/com/owncloud/android/authentication/AccountUtils.java
+++ b/src/com/owncloud/android/authentication/AccountUtils.java
@@ -56,8 +56,7 @@ public class AccountUtils {
* account). If none is available and valid, returns null.
*/
public static Account getCurrentOwnCloudAccount(Context context) {
- Account[] ocAccounts = AccountManager.get(context).getAccountsByType(
- MainApp.getAccountType());
+ Account[] ocAccounts = getAccounts(context);
Account defaultAccount = null;
SharedPreferences appPreferences = PreferenceManager
@@ -83,10 +82,14 @@ public static Account getCurrentOwnCloudAccount(Context context) {
return defaultAccount;
}
+ public static Account[] getAccounts(Context context) {
+ AccountManager accountManager = AccountManager.get(context);
+ return accountManager.getAccountsByType(MainApp.getAccountType());
+ }
+
public static boolean exists(Account account, Context context) {
- Account[] ocAccounts = AccountManager.get(context).getAccountsByType(
- MainApp.getAccountType());
+ Account[] ocAccounts = getAccounts(context);
if (account != null && account.name != null) {
int lastAtPos = account.name.lastIndexOf("@");
@@ -128,10 +131,8 @@ public static Account getOwnCloudAccountByName(Context context, String accountNa
public static boolean setCurrentOwnCloudAccount(Context context, String accountName) {
boolean result = false;
if (accountName != null) {
- Account[] ocAccounts = AccountManager.get(context).getAccountsByType(
- MainApp.getAccountType());
boolean found;
- for (Account account : ocAccounts) {
+ for (Account account : getAccounts(context)) {
found = (account.name.equals(accountName));
if (found) {
SharedPreferences.Editor appPrefs = PreferenceManager
diff --git a/src/com/owncloud/android/providers/DocumentsStorageProvider.java b/src/com/owncloud/android/providers/DocumentsStorageProvider.java
new file mode 100644
index 00000000000..85942dd5a84
--- /dev/null
+++ b/src/com/owncloud/android/providers/DocumentsStorageProvider.java
@@ -0,0 +1,208 @@
+/**
+ * ownCloud Android client application
+ *
+ * @author Bartosz Przybylski
+ * Copyright (C) 2015 Bartosz Przybylski
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package com.owncloud.android.providers;
+
+import android.accounts.Account;
+import android.annotation.TargetApi;
+import android.content.ContentResolver;
+import android.content.Intent;
+import android.content.res.AssetFileDescriptor;
+import android.database.Cursor;
+import android.graphics.Point;
+import android.os.Build;
+import android.os.CancellationSignal;
+import android.os.ParcelFileDescriptor;
+import android.provider.DocumentsProvider;
+
+import com.owncloud.android.authentication.AccountUtils;
+import com.owncloud.android.datamodel.FileDataStorageManager;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.files.services.FileDownloader;
+import com.owncloud.android.providers.cursors.FileCursor;
+import com.owncloud.android.providers.cursors.RootCursor;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Vector;
+
+@TargetApi(Build.VERSION_CODES.KITKAT)
+public class DocumentsStorageProvider extends DocumentsProvider {
+
+ private FileDataStorageManager mCurrentStorageManager = null;
+ private static Map mRootIdToStorageManager;
+
+ @Override
+ public Cursor queryRoots(String[] projection) throws FileNotFoundException {
+ initiateStorageMap();
+
+ final RootCursor result = new RootCursor(projection);
+
+ for (Account account : AccountUtils.getAccounts(getContext()))
+ result.addRoot(account, getContext());
+
+ return result;
+ }
+
+ @Override
+ public Cursor queryDocument(String documentId, String[] projection) throws FileNotFoundException {
+ final long docId = Long.parseLong(documentId);
+ updateCurrentStorageManagerIfNeeded(docId);
+
+ final FileCursor result = new FileCursor(projection);
+ result.addFile(mCurrentStorageManager.getFileById(docId));
+
+ return result;
+ }
+
+ @Override
+ public Cursor queryChildDocuments(String parentDocumentId, String[] projection, String sortOrder)
+ throws FileNotFoundException {
+
+ final long folderId = Long.parseLong(parentDocumentId);
+ updateCurrentStorageManagerIfNeeded(folderId);
+
+ final FileCursor result = new FileCursor(projection);
+
+ final OCFile browsedDir = mCurrentStorageManager.getFileById(folderId);
+ for (OCFile file : mCurrentStorageManager.getFolderContent(browsedDir))
+ result.addFile(file);
+
+ return result;
+ }
+
+ @Override
+ public ParcelFileDescriptor openDocument(String documentId, String mode, CancellationSignal cancellationSignal)
+ throws FileNotFoundException {
+ final long docId = Long.parseLong(documentId);
+ updateCurrentStorageManagerIfNeeded(docId);
+
+ OCFile file = mCurrentStorageManager.getFileById(docId);
+
+ if (!file.isDown()) {
+
+ Intent i = new Intent(getContext(), FileDownloader.class);
+ i.putExtra(FileDownloader.EXTRA_ACCOUNT, mCurrentStorageManager.getAccount());
+ i.putExtra(FileDownloader.EXTRA_FILE, file);
+ getContext().startService(i);
+
+ do {
+ if (!waitOrGetCancelled(cancellationSignal))
+ return null;
+ file = mCurrentStorageManager.getFileById(docId);
+
+ } while (!file.isDown());
+ }
+
+ return ParcelFileDescriptor.open(
+ new File(file.getStoragePath()), ParcelFileDescriptor.MODE_READ_ONLY);
+ }
+
+ @Override
+ public boolean onCreate() {
+ return true;
+ }
+
+ @Override
+ public AssetFileDescriptor openDocumentThumbnail(String documentId, Point sizeHint, CancellationSignal signal) throws FileNotFoundException {
+ long docId = Long.parseLong(documentId);
+ updateCurrentStorageManagerIfNeeded(docId);
+
+ OCFile file = mCurrentStorageManager.getFileById(docId);
+
+ File realFile = new File(file.getStoragePath());
+
+ return new AssetFileDescriptor(
+ ParcelFileDescriptor.open(realFile, ParcelFileDescriptor.MODE_READ_ONLY),
+ 0,
+ AssetFileDescriptor.UNKNOWN_LENGTH);
+ }
+
+ @Override
+ public Cursor querySearchDocuments(String rootId, String query, String[] projection) throws FileNotFoundException {
+ updateCurrentStorageManagerIfNeeded(rootId);
+
+ OCFile root = mCurrentStorageManager.getFileByPath("/");
+ FileCursor result = new FileCursor(projection);
+
+ for (OCFile f : findFiles(root, query))
+ result.addFile(f);
+
+ return result;
+ }
+
+ private void updateCurrentStorageManagerIfNeeded(long docId) {
+ if (mCurrentStorageManager == null ||
+ (mRootIdToStorageManager.containsKey(docId) &&
+ mCurrentStorageManager != mRootIdToStorageManager.get(docId))) {
+ mCurrentStorageManager = mRootIdToStorageManager.get(docId);
+ }
+ }
+
+ private void updateCurrentStorageManagerIfNeeded(String rootId) {
+ for (FileDataStorageManager data : mRootIdToStorageManager.values())
+ if (data.getAccount().name.equals(rootId))
+ mCurrentStorageManager = data;
+ }
+
+ private void initiateStorageMap() {
+
+ mRootIdToStorageManager = new HashMap();
+
+ ContentResolver contentResolver = getContext().getContentResolver();
+
+ for (Account account : AccountUtils.getAccounts(getContext())) {
+ final FileDataStorageManager storageManager =
+ new FileDataStorageManager(account, contentResolver);
+ final OCFile rootDir = storageManager.getFileByPath("/");
+ mRootIdToStorageManager.put(rootDir.getFileId(), storageManager);
+ }
+
+ }
+
+ private boolean waitOrGetCancelled(CancellationSignal cancellationSignal) {
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ return false;
+ }
+
+ if (cancellationSignal != null && cancellationSignal.isCanceled())
+ return false;
+
+ return true;
+ }
+
+ Vector findFiles(OCFile root, String query) {
+ Vector result = new Vector();
+ for (OCFile f : mCurrentStorageManager.getFolderContent(root)) {
+ if (f.isFolder()) {
+ result.addAll(findFiles(f, query));
+ } else {
+ if (f.getFileName().contains(query))
+ result.add(f);
+ }
+ }
+ return result;
+ }
+}
diff --git a/src/com/owncloud/android/providers/cursors/FileCursor.java b/src/com/owncloud/android/providers/cursors/FileCursor.java
new file mode 100644
index 00000000000..9d4b9d8cc0d
--- /dev/null
+++ b/src/com/owncloud/android/providers/cursors/FileCursor.java
@@ -0,0 +1,61 @@
+/**
+ * ownCloud Android client application
+ *
+ * @author Bartosz Przybylski
+ * Copyright (C) 2015 Bartosz Przybylski
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package com.owncloud.android.providers.cursors;
+
+import android.annotation.TargetApi;
+import android.database.MatrixCursor;
+import android.os.Build;
+import android.provider.DocumentsContract.Document;
+
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.utils.MimetypeIconUtil;
+
+@TargetApi(Build.VERSION_CODES.KITKAT)
+public class FileCursor extends MatrixCursor {
+
+ private static final String[] DEFAULT_DOCUMENT_PROJECTION = new String[] {
+ Document.COLUMN_DOCUMENT_ID, Document.COLUMN_DISPLAY_NAME,
+ Document.COLUMN_MIME_TYPE, Document.COLUMN_SIZE,
+ Document.COLUMN_FLAGS, Document.COLUMN_LAST_MODIFIED
+ };
+
+ public FileCursor(String[] projection) {
+ super(projection != null ? projection : DEFAULT_DOCUMENT_PROJECTION);
+ }
+
+ public void addFile(OCFile file) {
+ if (file == null) return;
+
+ final int iconRes = MimetypeIconUtil.getFileTypeIconId(file.getMimetype(), file.getFileName());
+ final String mimeType = file.isFolder() ? Document.MIME_TYPE_DIR : file.getMimetype();
+ final String imagePath = file.isImage() && file.isDown() ? file.getStoragePath() : null;
+ int flags = imagePath != null ? Document.FLAG_SUPPORTS_THUMBNAIL : 0;
+
+ newRow().add(Document.COLUMN_DOCUMENT_ID, Long.toString(file.getFileId()))
+ .add(Document.COLUMN_DISPLAY_NAME, file.getFileName())
+ .add(Document.COLUMN_LAST_MODIFIED, file.getModificationTimestamp())
+ .add(Document.COLUMN_SIZE, file.getFileLength())
+ .add(Document.COLUMN_FLAGS, flags)
+ .add(Document.COLUMN_ICON, iconRes)
+ .add(Document.COLUMN_MIME_TYPE, mimeType);
+ }
+}
diff --git a/src/com/owncloud/android/providers/cursors/RootCursor.java b/src/com/owncloud/android/providers/cursors/RootCursor.java
new file mode 100644
index 00000000000..cbf63d96bf8
--- /dev/null
+++ b/src/com/owncloud/android/providers/cursors/RootCursor.java
@@ -0,0 +1,62 @@
+/**
+ * ownCloud Android client application
+ *
+ * @author Bartosz Przybylski
+ * Copyright (C) 2015 Bartosz Przybylski
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package com.owncloud.android.providers.cursors;
+
+import android.accounts.Account;
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.database.MatrixCursor;
+import android.os.Build;
+import android.provider.DocumentsContract.Root;
+
+import com.owncloud.android.R;
+import com.owncloud.android.datamodel.FileDataStorageManager;
+import com.owncloud.android.datamodel.OCFile;
+
+
+@TargetApi(Build.VERSION_CODES.KITKAT)
+public class RootCursor extends MatrixCursor {
+
+ private static final String[] DEFAULT_ROOT_PROJECTION = new String[] {
+ Root.COLUMN_ROOT_ID, Root.COLUMN_FLAGS, Root.COLUMN_ICON, Root.COLUMN_TITLE,
+ Root.COLUMN_DOCUMENT_ID, Root.COLUMN_AVAILABLE_BYTES, Root.COLUMN_SUMMARY,
+ Root.COLUMN_FLAGS
+ };
+
+ public RootCursor(String[] projection) {
+ super(projection != null ? projection : DEFAULT_ROOT_PROJECTION);
+ }
+
+ public void addRoot(Account account, Context context) {
+ final FileDataStorageManager manager =
+ new FileDataStorageManager(account, context.getContentResolver());
+ final OCFile mainDir = manager.getFileByPath("/");
+ newRow().add(Root.COLUMN_ROOT_ID, account.name)
+ .add(Root.COLUMN_DOCUMENT_ID, mainDir.getFileId())
+ .add(Root.COLUMN_SUMMARY, account.name)
+ .add(Root.COLUMN_TITLE, context.getString(R.string.app_name))
+ .add(Root.COLUMN_ICON, R.drawable.icon)
+ .add(Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_SEARCH);
+
+ }
+
+}