|
@@ -0,0 +1,216 @@
|
|
|
+/**
|
|
|
+ * nextCloud Android client application
|
|
|
+ *
|
|
|
+ * @author Bartosz Przybylski
|
|
|
+ * Copyright (C) 2016 Bartosz Przybylski <bart.p.pl@gmail.com>
|
|
|
+ *
|
|
|
+ * 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 <http://www.gnu.org/licenses/>.
|
|
|
+ *
|
|
|
+ */
|
|
|
+
|
|
|
+package org.nextcloud.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 org.nextcloud.providers.cursors.FileCursor;
|
|
|
+import org.nextcloud.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<Long, FileDataStorageManager> 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);
|
|
|
+ OCFile file = mCurrentStorageManager.getFileById(docId);
|
|
|
+ if (file != null)
|
|
|
+ result.addFile(file);
|
|
|
+
|
|
|
+ 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<Long, FileDataStorageManager>();
|
|
|
+
|
|
|
+ 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<OCFile> findFiles(OCFile root, String query) {
|
|
|
+ Vector<OCFile> result = new Vector<OCFile>();
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+}
|