• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 package com.android.documentsui.model;
18 
19 import android.content.ContentProviderClient;
20 import android.content.ContentResolver;
21 import android.database.Cursor;
22 import android.net.Uri;
23 import android.os.Parcel;
24 import android.os.Parcelable;
25 import android.provider.DocumentsContract;
26 import android.provider.DocumentsContract.Document;
27 import android.provider.DocumentsProvider;
28 
29 import com.android.documentsui.DocumentsApplication;
30 import com.android.documentsui.RootCursorWrapper;
31 
32 import libcore.io.IoUtils;
33 
34 import java.io.DataInputStream;
35 import java.io.DataOutputStream;
36 import java.io.FileNotFoundException;
37 import java.io.IOException;
38 import java.net.ProtocolException;
39 
40 /**
41  * Representation of a {@link Document}.
42  */
43 public class DocumentInfo implements Durable, Parcelable {
44     private static final int VERSION_INIT = 1;
45     private static final int VERSION_SPLIT_URI = 2;
46 
47     public String authority;
48     public String documentId;
49     public String mimeType;
50     public String displayName;
51     public long lastModified;
52     public int flags;
53     public String summary;
54     public long size;
55     public int icon;
56 
57     /** Derived fields that aren't persisted */
58     public Uri derivedUri;
59 
DocumentInfo()60     public DocumentInfo() {
61         reset();
62     }
63 
64     @Override
reset()65     public void reset() {
66         authority = null;
67         documentId = null;
68         mimeType = null;
69         displayName = null;
70         lastModified = -1;
71         flags = 0;
72         summary = null;
73         size = -1;
74         icon = 0;
75 
76         derivedUri = null;
77     }
78 
79     @Override
read(DataInputStream in)80     public void read(DataInputStream in) throws IOException {
81         final int version = in.readInt();
82         switch (version) {
83             case VERSION_INIT:
84                 throw new ProtocolException("Ignored upgrade");
85             case VERSION_SPLIT_URI:
86                 authority = DurableUtils.readNullableString(in);
87                 documentId = DurableUtils.readNullableString(in);
88                 mimeType = DurableUtils.readNullableString(in);
89                 displayName = DurableUtils.readNullableString(in);
90                 lastModified = in.readLong();
91                 flags = in.readInt();
92                 summary = DurableUtils.readNullableString(in);
93                 size = in.readLong();
94                 icon = in.readInt();
95                 deriveFields();
96                 break;
97             default:
98                 throw new ProtocolException("Unknown version " + version);
99         }
100     }
101 
102     @Override
write(DataOutputStream out)103     public void write(DataOutputStream out) throws IOException {
104         out.writeInt(VERSION_SPLIT_URI);
105         DurableUtils.writeNullableString(out, authority);
106         DurableUtils.writeNullableString(out, documentId);
107         DurableUtils.writeNullableString(out, mimeType);
108         DurableUtils.writeNullableString(out, displayName);
109         out.writeLong(lastModified);
110         out.writeInt(flags);
111         DurableUtils.writeNullableString(out, summary);
112         out.writeLong(size);
113         out.writeInt(icon);
114     }
115 
116     @Override
describeContents()117     public int describeContents() {
118         return 0;
119     }
120 
121     @Override
writeToParcel(Parcel dest, int flags)122     public void writeToParcel(Parcel dest, int flags) {
123         DurableUtils.writeToParcel(dest, this);
124     }
125 
126     public static final Creator<DocumentInfo> CREATOR = new Creator<DocumentInfo>() {
127         @Override
128         public DocumentInfo createFromParcel(Parcel in) {
129             final DocumentInfo doc = new DocumentInfo();
130             DurableUtils.readFromParcel(in, doc);
131             return doc;
132         }
133 
134         @Override
135         public DocumentInfo[] newArray(int size) {
136             return new DocumentInfo[size];
137         }
138     };
139 
fromDirectoryCursor(Cursor cursor)140     public static DocumentInfo fromDirectoryCursor(Cursor cursor) {
141         final String authority = getCursorString(cursor, RootCursorWrapper.COLUMN_AUTHORITY);
142         return fromCursor(cursor, authority);
143     }
144 
fromCursor(Cursor cursor, String authority)145     public static DocumentInfo fromCursor(Cursor cursor, String authority) {
146         final DocumentInfo info = new DocumentInfo();
147         info.updateFromCursor(cursor, authority);
148         return info;
149     }
150 
updateFromCursor(Cursor cursor, String authority)151     public void updateFromCursor(Cursor cursor, String authority) {
152         this.authority = authority;
153         this.documentId = getCursorString(cursor, Document.COLUMN_DOCUMENT_ID);
154         this.mimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
155         this.documentId = getCursorString(cursor, Document.COLUMN_DOCUMENT_ID);
156         this.mimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
157         this.displayName = getCursorString(cursor, Document.COLUMN_DISPLAY_NAME);
158         this.lastModified = getCursorLong(cursor, Document.COLUMN_LAST_MODIFIED);
159         this.flags = getCursorInt(cursor, Document.COLUMN_FLAGS);
160         this.summary = getCursorString(cursor, Document.COLUMN_SUMMARY);
161         this.size = getCursorLong(cursor, Document.COLUMN_SIZE);
162         this.icon = getCursorInt(cursor, Document.COLUMN_ICON);
163         this.deriveFields();
164     }
165 
fromUri(ContentResolver resolver, Uri uri)166     public static DocumentInfo fromUri(ContentResolver resolver, Uri uri)
167             throws FileNotFoundException {
168         final DocumentInfo info = new DocumentInfo();
169         info.updateFromUri(resolver, uri);
170         return info;
171     }
172 
173     /**
174      * Update a possibly stale restored document against a live
175      * {@link DocumentsProvider}.
176      */
updateSelf(ContentResolver resolver)177     public void updateSelf(ContentResolver resolver) throws FileNotFoundException {
178         updateFromUri(resolver, derivedUri);
179     }
180 
updateFromUri(ContentResolver resolver, Uri uri)181     public void updateFromUri(ContentResolver resolver, Uri uri) throws FileNotFoundException {
182         ContentProviderClient client = null;
183         Cursor cursor = null;
184         try {
185             client = DocumentsApplication.acquireUnstableProviderOrThrow(
186                     resolver, uri.getAuthority());
187             cursor = client.query(uri, null, null, null, null);
188             if (!cursor.moveToFirst()) {
189                 throw new FileNotFoundException("Missing details for " + uri);
190             }
191             updateFromCursor(cursor, uri.getAuthority());
192         } catch (Throwable t) {
193             throw asFileNotFoundException(t);
194         } finally {
195             IoUtils.closeQuietly(cursor);
196             ContentProviderClient.releaseQuietly(client);
197         }
198     }
199 
deriveFields()200     private void deriveFields() {
201         derivedUri = DocumentsContract.buildDocumentUri(authority, documentId);
202     }
203 
204     @Override
toString()205     public String toString() {
206         return "Document{docId=" + documentId + ", name=" + displayName + "}";
207     }
208 
isCreateSupported()209     public boolean isCreateSupported() {
210         return (flags & Document.FLAG_DIR_SUPPORTS_CREATE) != 0;
211     }
212 
isThumbnailSupported()213     public boolean isThumbnailSupported() {
214         return (flags & Document.FLAG_SUPPORTS_THUMBNAIL) != 0;
215     }
216 
isDirectory()217     public boolean isDirectory() {
218         return Document.MIME_TYPE_DIR.equals(mimeType);
219     }
220 
isGridPreferred()221     public boolean isGridPreferred() {
222         return (flags & Document.FLAG_DIR_PREFERS_GRID) != 0;
223     }
224 
isDeleteSupported()225     public boolean isDeleteSupported() {
226         return (flags & Document.FLAG_SUPPORTS_DELETE) != 0;
227     }
228 
isGridTitlesHidden()229     public boolean isGridTitlesHidden() {
230         return (flags & Document.FLAG_DIR_HIDE_GRID_TITLES) != 0;
231     }
232 
getCursorString(Cursor cursor, String columnName)233     public static String getCursorString(Cursor cursor, String columnName) {
234         final int index = cursor.getColumnIndex(columnName);
235         return (index != -1) ? cursor.getString(index) : null;
236     }
237 
238     /**
239      * Missing or null values are returned as -1.
240      */
getCursorLong(Cursor cursor, String columnName)241     public static long getCursorLong(Cursor cursor, String columnName) {
242         final int index = cursor.getColumnIndex(columnName);
243         if (index == -1) return -1;
244         final String value = cursor.getString(index);
245         if (value == null) return -1;
246         try {
247             return Long.parseLong(value);
248         } catch (NumberFormatException e) {
249             return -1;
250         }
251     }
252 
253     /**
254      * Missing or null values are returned as 0.
255      */
getCursorInt(Cursor cursor, String columnName)256     public static int getCursorInt(Cursor cursor, String columnName) {
257         final int index = cursor.getColumnIndex(columnName);
258         return (index != -1) ? cursor.getInt(index) : 0;
259     }
260 
asFileNotFoundException(Throwable t)261     public static FileNotFoundException asFileNotFoundException(Throwable t)
262             throws FileNotFoundException {
263         if (t instanceof FileNotFoundException) {
264             throw (FileNotFoundException) t;
265         }
266         final FileNotFoundException fnfe = new FileNotFoundException(t.getMessage());
267         fnfe.initCause(t);
268         throw fnfe;
269     }
270 
compareToIgnoreCaseNullable(String lhs, String rhs)271     public static int compareToIgnoreCaseNullable(String lhs, String rhs) {
272         if (lhs == null) return -1;
273         if (rhs == null) return 1;
274         return lhs.compareToIgnoreCase(rhs);
275     }
276 }
277