blob: 3028f1b675418d1cd1e51fb8b5092b897dfd1622 [file] [log] [blame]
Steve McKaydef48682016-10-03 09:07:38 -07001/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.documentsui;
18
Jeff Sharkeya4ff00f2018-07-09 14:57:51 -060019import androidx.annotation.Nullable;
Jeff Sharkey2c0b4852019-02-15 15:53:47 -070020
21import static android.content.ContentResolver.wrap;
22
Garfield Tan16868832016-09-26 10:01:45 -070023import android.content.ContentProviderClient;
Garfield Tan2a837422016-10-19 11:50:45 -070024import android.content.ContentResolver;
Steve McKaydef48682016-10-03 09:07:38 -070025import android.content.Context;
Garfield Tan16868832016-09-26 10:01:45 -070026import android.database.Cursor;
Steve McKaydef48682016-10-03 09:07:38 -070027import android.net.Uri;
Tomasz Mikolajewskic8fb30f2017-01-24 18:54:42 +090028import android.os.ParcelFileDescriptor;
Garfield Tan16868832016-09-26 10:01:45 -070029import android.os.RemoteException;
Steve McKaydef48682016-10-03 09:07:38 -070030import android.provider.DocumentsContract;
Garfield Tan2a837422016-10-19 11:50:45 -070031import android.provider.DocumentsContract.Path;
Steve McKaydef48682016-10-03 09:07:38 -070032import android.util.Log;
33
Tomasz Mikolajewskidbd6b8b2016-09-29 15:27:37 +090034import com.android.documentsui.archives.ArchivesProvider;
Steve McKaydef48682016-10-03 09:07:38 -070035import com.android.documentsui.base.DocumentInfo;
36import com.android.documentsui.base.RootInfo;
37
38import java.io.FileNotFoundException;
Garfield Tan16868832016-09-26 10:01:45 -070039import java.util.ArrayList;
40import java.util.List;
Steve McKaydef48682016-10-03 09:07:38 -070041
42/**
Garfield Tan2a837422016-10-19 11:50:45 -070043 * Provides synchronous access to {@link DocumentInfo} instances given some identifying information
44 * and some documents API.
Steve McKaydef48682016-10-03 09:07:38 -070045 */
46public interface DocumentsAccess {
47
48 @Nullable DocumentInfo getRootDocument(RootInfo root);
Steve McKaydef48682016-10-03 09:07:38 -070049 @Nullable DocumentInfo getDocument(Uri uri);
Tomasz Mikolajewskidbd6b8b2016-09-29 15:27:37 +090050 @Nullable DocumentInfo getArchiveDocument(Uri uri);
Steve McKaydef48682016-10-03 09:07:38 -070051
Garfield Tan2a837422016-10-19 11:50:45 -070052 boolean isDocumentUri(Uri uri);
Jeff Sharkey844989e2018-12-07 15:16:08 -070053 @Nullable Path findDocumentPath(Uri uri) throws RemoteException, FileNotFoundException;
Garfield Tan2a837422016-10-19 11:50:45 -070054
55 List<DocumentInfo> getDocuments(String authority, List<String> docIds) throws RemoteException;
Garfield Tan16868832016-09-26 10:01:45 -070056
Garfield Tan894d4872017-03-17 12:23:22 -070057 @Nullable Uri createDocument(DocumentInfo parentDoc, String mimeType, String displayName);
58
Steve McKaydef48682016-10-03 09:07:38 -070059 public static DocumentsAccess create(Context context) {
60 return new RuntimeDocumentAccess(context);
61 }
62
63 public final class RuntimeDocumentAccess implements DocumentsAccess {
64
65 private static final String TAG = "DocumentAccess";
66
67 private final Context mContext;
68
69 private RuntimeDocumentAccess(Context context) {
70 mContext = context;
71 }
72
73 @Override
74 public @Nullable DocumentInfo getRootDocument(RootInfo root) {
Garfield Tan16868832016-09-26 10:01:45 -070075 return getDocument(
Steve McKaydef48682016-10-03 09:07:38 -070076 DocumentsContract.buildDocumentUri(root.authority, root.documentId));
77 }
78
79 @Override
Garfield Tan16868832016-09-26 10:01:45 -070080 public @Nullable DocumentInfo getDocument(Uri uri) {
Steve McKaydef48682016-10-03 09:07:38 -070081 try {
82 return DocumentInfo.fromUri(mContext.getContentResolver(), uri);
83 } catch (FileNotFoundException e) {
84 Log.w(TAG, "Couldn't create DocumentInfo for uri: " + uri);
85 }
86
87 return null;
88 }
Tomasz Mikolajewskidbd6b8b2016-09-29 15:27:37 +090089
90 @Override
Garfield Tan2a837422016-10-19 11:50:45 -070091 public List<DocumentInfo> getDocuments(String authority, List<String> docIds)
92 throws RemoteException {
93
Garfield Tan16868832016-09-26 10:01:45 -070094 try(final ContentProviderClient client = DocumentsApplication
95 .acquireUnstableProviderOrThrow(mContext.getContentResolver(), authority)) {
96
97 List<DocumentInfo> result = new ArrayList<>(docIds.size());
98 for (String docId : docIds) {
99 final Uri uri = DocumentsContract.buildDocumentUri(authority, docId);
100 try (final Cursor cursor = client.query(uri, null, null, null, null)) {
101 if (!cursor.moveToNext()) {
102 Log.e(TAG, "Couldn't create DocumentInfo for Uri: " + uri);
Garfield Tan2a837422016-10-19 11:50:45 -0700103 throw new RemoteException("Failed to move cursor.");
Garfield Tan16868832016-09-26 10:01:45 -0700104 }
105
106 result.add(DocumentInfo.fromCursor(cursor, authority));
Garfield Tan16868832016-09-26 10:01:45 -0700107 }
108 }
109
110 return result;
Garfield Tan16868832016-09-26 10:01:45 -0700111 }
112 }
113
114 @Override
Tomasz Mikolajewskidbd6b8b2016-09-29 15:27:37 +0900115 public DocumentInfo getArchiveDocument(Uri uri) {
Tomasz Mikolajewskic8fb30f2017-01-24 18:54:42 +0900116 return getDocument(ArchivesProvider.buildUriForArchive(uri,
117 ParcelFileDescriptor.MODE_READ_ONLY));
Tomasz Mikolajewskidbd6b8b2016-09-29 15:27:37 +0900118 }
Garfield Tan2a837422016-10-19 11:50:45 -0700119
120 @Override
121 public boolean isDocumentUri(Uri uri) {
122 return DocumentsContract.isDocumentUri(mContext, uri);
123 }
124
125 @Override
Jeff Sharkey844989e2018-12-07 15:16:08 -0700126 public Path findDocumentPath(Uri docUri) throws RemoteException, FileNotFoundException {
Garfield Tan2a837422016-10-19 11:50:45 -0700127 final ContentResolver resolver = mContext.getContentResolver();
128 try (final ContentProviderClient client = DocumentsApplication
129 .acquireUnstableProviderOrThrow(resolver, docUri.getAuthority())) {
Jeff Sharkey2c0b4852019-02-15 15:53:47 -0700130 return DocumentsContract.findDocumentPath(wrap(client), docUri);
Garfield Tan2a837422016-10-19 11:50:45 -0700131 }
132 }
Garfield Tan894d4872017-03-17 12:23:22 -0700133
134 @Override
135 public Uri createDocument(DocumentInfo parentDoc, String mimeType, String displayName) {
136 final ContentResolver resolver = mContext.getContentResolver();
137 try (ContentProviderClient client = DocumentsApplication.acquireUnstableProviderOrThrow(
138 resolver, parentDoc.derivedUri.getAuthority())) {
139 return DocumentsContract.createDocument(
Jeff Sharkey2c0b4852019-02-15 15:53:47 -0700140 wrap(client), parentDoc.derivedUri, mimeType, displayName);
Garfield Tan894d4872017-03-17 12:23:22 -0700141 } catch (Exception e) {
142 Log.w(TAG, "Failed to create document", e);
143 return null;
144 }
145 }
Steve McKaydef48682016-10-03 09:07:38 -0700146 }
147}