1ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey/*
2ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey * Copyright (C) 2013 The Android Open Source Project
3ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey *
4ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey * Licensed under the Apache License, Version 2.0 (the "License");
5ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey * you may not use this file except in compliance with the License.
6ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey * You may obtain a copy of the License at
7ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey *
8ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey *      http://www.apache.org/licenses/LICENSE-2.0
9ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey *
10ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey * Unless required by applicable law or agreed to in writing, software
11ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey * distributed under the License is distributed on an "AS IS" BASIS,
12ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey * See the License for the specific language governing permissions and
14ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey * limitations under the License.
15ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey */
16ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey
17ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkeypackage com.android.documentsui.model;
18ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey
19ded77187ef53341765fcab8e29cda94810fc2ca5Jeff Sharkeyimport android.content.ContentProviderClient;
20ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkeyimport android.content.ContentResolver;
21ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkeyimport android.database.Cursor;
22ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkeyimport android.net.Uri;
23d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkeyimport android.os.Parcel;
24d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkeyimport android.os.Parcelable;
25ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkeyimport android.provider.DocumentsContract;
26ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkeyimport android.provider.DocumentsContract.Document;
277aa7601c09ab5d87cc15a0ed9a8f511d494a4cbcJeff Sharkeyimport android.provider.DocumentsProvider;
28d3afdeebeb9dcfbb5f24e4afac988e2e96de26deSteve McKayimport android.support.annotation.VisibleForTesting;
29ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey
307aa7601c09ab5d87cc15a0ed9a8f511d494a4cbcJeff Sharkeyimport com.android.documentsui.DocumentsApplication;
31251097b3789632000ccdaf7fb7d66a82ff37d882Jeff Sharkeyimport com.android.documentsui.RootCursorWrapper;
32ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey
330c2d31bfa113c2848620ac05c916802410b71da1Jeff Sharkeyimport libcore.io.IoUtils;
340c2d31bfa113c2848620ac05c916802410b71da1Jeff Sharkey
35b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkeyimport java.io.DataInputStream;
36b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkeyimport java.io.DataOutputStream;
370c2d31bfa113c2848620ac05c916802410b71da1Jeff Sharkeyimport java.io.FileNotFoundException;
38b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkeyimport java.io.IOException;
39b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkeyimport java.net.ProtocolException;
4030551a257ca39f716a1d83c5cfd64d9c20efa6adSteve McKayimport java.util.Objects;
41ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey
42ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey/**
43ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * Representation of a {@link Document}.
44ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey */
45d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkeypublic class DocumentInfo implements Durable, Parcelable {
46b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey    private static final int VERSION_INIT = 1;
47d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey    private static final int VERSION_SPLIT_URI = 2;
48b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey
49d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey    public String authority;
50d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey    public String documentId;
515dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey    public String mimeType;
525dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey    public String displayName;
535dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey    public long lastModified;
545dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey    public int flags;
555dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey    public String summary;
565dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey    public long size;
575dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey    public int icon;
58ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey
59d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey    /** Derived fields that aren't persisted */
60d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey    public Uri derivedUri;
61d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey
62b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey    public DocumentInfo() {
63b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey        reset();
64b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey    }
65b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey
66b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey    @Override
67b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey    public void reset() {
68d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey        authority = null;
69d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey        documentId = null;
70b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey        mimeType = null;
71b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey        displayName = null;
72b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey        lastModified = -1;
73b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey        flags = 0;
74b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey        summary = null;
75b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey        size = -1;
76b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey        icon = 0;
77d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey        derivedUri = null;
78b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey    }
79b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey
80b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey    @Override
81b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey    public void read(DataInputStream in) throws IOException {
82b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey        final int version = in.readInt();
83b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey        switch (version) {
84b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey            case VERSION_INIT:
85d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey                throw new ProtocolException("Ignored upgrade");
86d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey            case VERSION_SPLIT_URI:
87d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey                authority = DurableUtils.readNullableString(in);
88d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey                documentId = DurableUtils.readNullableString(in);
89b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey                mimeType = DurableUtils.readNullableString(in);
90b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey                displayName = DurableUtils.readNullableString(in);
91b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey                lastModified = in.readLong();
92b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey                flags = in.readInt();
93b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey                summary = DurableUtils.readNullableString(in);
94b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey                size = in.readLong();
95b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey                icon = in.readInt();
96d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey                deriveFields();
97b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey                break;
98b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey            default:
99b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey                throw new ProtocolException("Unknown version " + version);
100b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey        }
101b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey    }
102b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey
103b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey    @Override
104b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey    public void write(DataOutputStream out) throws IOException {
105d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey        out.writeInt(VERSION_SPLIT_URI);
106d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey        DurableUtils.writeNullableString(out, authority);
107d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey        DurableUtils.writeNullableString(out, documentId);
108b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey        DurableUtils.writeNullableString(out, mimeType);
109b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey        DurableUtils.writeNullableString(out, displayName);
110b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey        out.writeLong(lastModified);
111b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey        out.writeInt(flags);
112b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey        DurableUtils.writeNullableString(out, summary);
113b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey        out.writeLong(size);
114b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey        out.writeInt(icon);
115b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey    }
116b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey
117d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey    @Override
118d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey    public int describeContents() {
119d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey        return 0;
120d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey    }
121d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey
122d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey    @Override
123d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey    public void writeToParcel(Parcel dest, int flags) {
124d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey        DurableUtils.writeToParcel(dest, this);
125d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey    }
126d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey
127d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey    public static final Creator<DocumentInfo> CREATOR = new Creator<DocumentInfo>() {
128d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey        @Override
129d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey        public DocumentInfo createFromParcel(Parcel in) {
130d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey            final DocumentInfo doc = new DocumentInfo();
131d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey            DurableUtils.readFromParcel(in, doc);
132d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey            return doc;
133d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey        }
134d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey
135d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey        @Override
136d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey        public DocumentInfo[] newArray(int size) {
137d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey            return new DocumentInfo[size];
138d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey        }
139d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey    };
140d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey
141251097b3789632000ccdaf7fb7d66a82ff37d882Jeff Sharkey    public static DocumentInfo fromDirectoryCursor(Cursor cursor) {
142dcc68fdd0ca1f0d2d2dfb979dd837ac2dd2e16f3Steve McKay        assert(cursor != null);
143251097b3789632000ccdaf7fb7d66a82ff37d882Jeff Sharkey        final String authority = getCursorString(cursor, RootCursorWrapper.COLUMN_AUTHORITY);
144d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey        return fromCursor(cursor, authority);
145d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey    }
146d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey
147d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey    public static DocumentInfo fromCursor(Cursor cursor, String authority) {
148dcc68fdd0ca1f0d2d2dfb979dd837ac2dd2e16f3Steve McKay        assert(cursor != null);
149deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey        final DocumentInfo info = new DocumentInfo();
150deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey        info.updateFromCursor(cursor, authority);
151deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey        return info;
152ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey    }
153ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey
154deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey    public void updateFromCursor(Cursor cursor, String authority) {
155deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey        this.authority = authority;
156deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey        this.documentId = getCursorString(cursor, Document.COLUMN_DOCUMENT_ID);
157deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey        this.mimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
158deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey        this.displayName = getCursorString(cursor, Document.COLUMN_DISPLAY_NAME);
159deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey        this.lastModified = getCursorLong(cursor, Document.COLUMN_LAST_MODIFIED);
160deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey        this.flags = getCursorInt(cursor, Document.COLUMN_FLAGS);
161deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey        this.summary = getCursorString(cursor, Document.COLUMN_SUMMARY);
162deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey        this.size = getCursorLong(cursor, Document.COLUMN_SIZE);
163deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey        this.icon = getCursorInt(cursor, Document.COLUMN_ICON);
164deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey        this.deriveFields();
165deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey    }
166deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey
167deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey    public static DocumentInfo fromUri(ContentResolver resolver, Uri uri)
168deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey            throws FileNotFoundException {
169deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey        final DocumentInfo info = new DocumentInfo();
170deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey        info.updateFromUri(resolver, uri);
171deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey        return info;
172deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey    }
173deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey
174deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey    /**
175deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey     * Update a possibly stale restored document against a live
176deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey     * {@link DocumentsProvider}.
177deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey     */
178deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey    public void updateSelf(ContentResolver resolver) throws FileNotFoundException {
179deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey        updateFromUri(resolver, derivedUri);
180deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey    }
181deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey
182deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey    public void updateFromUri(ContentResolver resolver, Uri uri) throws FileNotFoundException {
1837aa7601c09ab5d87cc15a0ed9a8f511d494a4cbcJeff Sharkey        ContentProviderClient client = null;
1840c2d31bfa113c2848620ac05c916802410b71da1Jeff Sharkey        Cursor cursor = null;
185ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey        try {
1867aa7601c09ab5d87cc15a0ed9a8f511d494a4cbcJeff Sharkey            client = DocumentsApplication.acquireUnstableProviderOrThrow(
1877aa7601c09ab5d87cc15a0ed9a8f511d494a4cbcJeff Sharkey                    resolver, uri.getAuthority());
188ded77187ef53341765fcab8e29cda94810fc2ca5Jeff Sharkey            cursor = client.query(uri, null, null, null, null);
189ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey            if (!cursor.moveToFirst()) {
1900c2d31bfa113c2848620ac05c916802410b71da1Jeff Sharkey                throw new FileNotFoundException("Missing details for " + uri);
191ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey            }
192deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey            updateFromCursor(cursor, uri.getAuthority());
1930c2d31bfa113c2848620ac05c916802410b71da1Jeff Sharkey        } catch (Throwable t) {
1940c2d31bfa113c2848620ac05c916802410b71da1Jeff Sharkey            throw asFileNotFoundException(t);
195ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey        } finally {
1960c2d31bfa113c2848620ac05c916802410b71da1Jeff Sharkey            IoUtils.closeQuietly(cursor);
1977aa7601c09ab5d87cc15a0ed9a8f511d494a4cbcJeff Sharkey            ContentProviderClient.releaseQuietly(client);
198ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey        }
199ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey    }
200ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey
201d3afdeebeb9dcfbb5f24e4afac988e2e96de26deSteve McKay    @VisibleForTesting
202d3afdeebeb9dcfbb5f24e4afac988e2e96de26deSteve McKay    void deriveFields() {
203d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey        derivedUri = DocumentsContract.buildDocumentUri(authority, documentId);
204d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey    }
205d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey
206ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey    @Override
207ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey    public String toString() {
208d3afdeebeb9dcfbb5f24e4afac988e2e96de26deSteve McKay        return "Document{"
209d3afdeebeb9dcfbb5f24e4afac988e2e96de26deSteve McKay                + "docId=" + documentId
210d3afdeebeb9dcfbb5f24e4afac988e2e96de26deSteve McKay                + ", name=" + displayName
21127d20a3024d477bc23055825e0f05203982539c3Steve McKay                + ", isContainer=" + isContainer()
212d3afdeebeb9dcfbb5f24e4afac988e2e96de26deSteve McKay                + ", isDirectory=" + isDirectory()
21327d20a3024d477bc23055825e0f05203982539c3Steve McKay                + ", isArchive=" + isArchive()
214168e464812341fdc64c3b85659b60114bee3b86eSteve McKay                + ", isPartial=" + isPartial()
21527d20a3024d477bc23055825e0f05203982539c3Steve McKay                + ", isVirtualDocument=" + isVirtualDocument()
21627d20a3024d477bc23055825e0f05203982539c3Steve McKay                + ", isDeleteSupported=" + isDeleteSupported()
21727d20a3024d477bc23055825e0f05203982539c3Steve McKay                + ", isCreateSupported=" + isCreateSupported()
21827d20a3024d477bc23055825e0f05203982539c3Steve McKay                + ", isRenameSupported=" + isRenameSupported()
219d3afdeebeb9dcfbb5f24e4afac988e2e96de26deSteve McKay                + "}";
220ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey    }
221ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey
222ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey    public boolean isCreateSupported() {
223ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey        return (flags & Document.FLAG_DIR_SUPPORTS_CREATE) != 0;
224ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey    }
225ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey
226ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey    public boolean isThumbnailSupported() {
227ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey        return (flags & Document.FLAG_SUPPORTS_THUMBNAIL) != 0;
228ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey    }
229ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey
230b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey    public boolean isDirectory() {
231ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey        return Document.MIME_TYPE_DIR.equals(mimeType);
232b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey    }
233b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey
2344eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey    public boolean isGridPreferred() {
235ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey        return (flags & Document.FLAG_DIR_PREFERS_GRID) != 0;
2364eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey    }
2374eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey
2384eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey    public boolean isDeleteSupported() {
239ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey        return (flags & Document.FLAG_SUPPORTS_DELETE) != 0;
2404eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey    }
2414eb407a832b7d6a2d62a535e5cab70b00a0bc8edJeff Sharkey
24227d20a3024d477bc23055825e0f05203982539c3Steve McKay    public boolean isRemoveSupported() {
24327d20a3024d477bc23055825e0f05203982539c3Steve McKay        return (flags & Document.FLAG_SUPPORTS_REMOVE) != 0;
24427d20a3024d477bc23055825e0f05203982539c3Steve McKay    }
24527d20a3024d477bc23055825e0f05203982539c3Steve McKay
2463b327ef9f9dec19612202b4b0b450966870a077fAga Wronska    public boolean isRenameSupported() {
2473b327ef9f9dec19612202b4b0b450966870a077fAga Wronska        return (flags & Document.FLAG_SUPPORTS_RENAME) != 0;
2483b327ef9f9dec19612202b4b0b450966870a077fAga Wronska    }
2493b327ef9f9dec19612202b4b0b450966870a077fAga Wronska
25039acff5a36ab0540981cdae3027ea1a45fe040e5Tomasz Mikolajewski    public boolean isArchive() {
25139acff5a36ab0540981cdae3027ea1a45fe040e5Tomasz Mikolajewski        return (flags & Document.FLAG_ARCHIVE) != 0;
25239acff5a36ab0540981cdae3027ea1a45fe040e5Tomasz Mikolajewski    }
25339acff5a36ab0540981cdae3027ea1a45fe040e5Tomasz Mikolajewski
254168e464812341fdc64c3b85659b60114bee3b86eSteve McKay    public boolean isPartial() {
255168e464812341fdc64c3b85659b60114bee3b86eSteve McKay        return (flags & Document.FLAG_PARTIAL) != 0;
256168e464812341fdc64c3b85659b60114bee3b86eSteve McKay    }
257168e464812341fdc64c3b85659b60114bee3b86eSteve McKay
25839acff5a36ab0540981cdae3027ea1a45fe040e5Tomasz Mikolajewski    public boolean isContainer() {
25939acff5a36ab0540981cdae3027ea1a45fe040e5Tomasz Mikolajewski        return isDirectory() || isArchive();
26039acff5a36ab0540981cdae3027ea1a45fe040e5Tomasz Mikolajewski    }
26139acff5a36ab0540981cdae3027ea1a45fe040e5Tomasz Mikolajewski
262470a3dbc5d9c299803ba407497458acefd34f546Tomasz Mikolajewski    public boolean isVirtualDocument() {
263470a3dbc5d9c299803ba407497458acefd34f546Tomasz Mikolajewski        return (flags & Document.FLAG_VIRTUAL_DOCUMENT) != 0;
264470a3dbc5d9c299803ba407497458acefd34f546Tomasz Mikolajewski    }
265470a3dbc5d9c299803ba407497458acefd34f546Tomasz Mikolajewski
266d3afdeebeb9dcfbb5f24e4afac988e2e96de26deSteve McKay    public int hashCode() {
267d3afdeebeb9dcfbb5f24e4afac988e2e96de26deSteve McKay        return derivedUri.hashCode() + mimeType.hashCode();
268d3afdeebeb9dcfbb5f24e4afac988e2e96de26deSteve McKay    }
269d3afdeebeb9dcfbb5f24e4afac988e2e96de26deSteve McKay
27030551a257ca39f716a1d83c5cfd64d9c20efa6adSteve McKay    public boolean equals(Object o) {
27130551a257ca39f716a1d83c5cfd64d9c20efa6adSteve McKay        if (o == null) {
272d3afdeebeb9dcfbb5f24e4afac988e2e96de26deSteve McKay            return false;
273d3afdeebeb9dcfbb5f24e4afac988e2e96de26deSteve McKay        }
274d3afdeebeb9dcfbb5f24e4afac988e2e96de26deSteve McKay
27530551a257ca39f716a1d83c5cfd64d9c20efa6adSteve McKay        if (this == o) {
27630551a257ca39f716a1d83c5cfd64d9c20efa6adSteve McKay            return true;
27730551a257ca39f716a1d83c5cfd64d9c20efa6adSteve McKay        }
27830551a257ca39f716a1d83c5cfd64d9c20efa6adSteve McKay
27930551a257ca39f716a1d83c5cfd64d9c20efa6adSteve McKay        if (o instanceof DocumentInfo) {
28030551a257ca39f716a1d83c5cfd64d9c20efa6adSteve McKay            DocumentInfo other = (DocumentInfo) o;
28130551a257ca39f716a1d83c5cfd64d9c20efa6adSteve McKay            // Uri + mime type should be totally unique.
28230551a257ca39f716a1d83c5cfd64d9c20efa6adSteve McKay            return Objects.equals(derivedUri, other.derivedUri)
28330551a257ca39f716a1d83c5cfd64d9c20efa6adSteve McKay                    && Objects.equals(mimeType, other.mimeType);
28430551a257ca39f716a1d83c5cfd64d9c20efa6adSteve McKay        }
28530551a257ca39f716a1d83c5cfd64d9c20efa6adSteve McKay
28630551a257ca39f716a1d83c5cfd64d9c20efa6adSteve McKay        return false;
287d3afdeebeb9dcfbb5f24e4afac988e2e96de26deSteve McKay    }
288d3afdeebeb9dcfbb5f24e4afac988e2e96de26deSteve McKay
289ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey    public static String getCursorString(Cursor cursor, String columnName) {
290b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey        final int index = cursor.getColumnIndex(columnName);
291b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey        return (index != -1) ? cursor.getString(index) : null;
292ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey    }
293ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey
294a5599ef636e37cb0b6474349936999be1afe6987Jeff Sharkey    /**
295a5599ef636e37cb0b6474349936999be1afe6987Jeff Sharkey     * Missing or null values are returned as -1.
296a5599ef636e37cb0b6474349936999be1afe6987Jeff Sharkey     */
297ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey    public static long getCursorLong(Cursor cursor, String columnName) {
298b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey        final int index = cursor.getColumnIndex(columnName);
299a5599ef636e37cb0b6474349936999be1afe6987Jeff Sharkey        if (index == -1) return -1;
300a5599ef636e37cb0b6474349936999be1afe6987Jeff Sharkey        final String value = cursor.getString(index);
301a5599ef636e37cb0b6474349936999be1afe6987Jeff Sharkey        if (value == null) return -1;
302a5599ef636e37cb0b6474349936999be1afe6987Jeff Sharkey        try {
303a5599ef636e37cb0b6474349936999be1afe6987Jeff Sharkey            return Long.parseLong(value);
304a5599ef636e37cb0b6474349936999be1afe6987Jeff Sharkey        } catch (NumberFormatException e) {
305a5599ef636e37cb0b6474349936999be1afe6987Jeff Sharkey            return -1;
306a5599ef636e37cb0b6474349936999be1afe6987Jeff Sharkey        }
307ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey    }
308ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey
309d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey    /**
310d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey     * Missing or null values are returned as 0.
311d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey     */
312ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey    public static int getCursorInt(Cursor cursor, String columnName) {
313b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey        final int index = cursor.getColumnIndex(columnName);
314b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey        return (index != -1) ? cursor.getInt(index) : 0;
315ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey    }
316ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey
3170c2d31bfa113c2848620ac05c916802410b71da1Jeff Sharkey    public static FileNotFoundException asFileNotFoundException(Throwable t)
3180c2d31bfa113c2848620ac05c916802410b71da1Jeff Sharkey            throws FileNotFoundException {
3190c2d31bfa113c2848620ac05c916802410b71da1Jeff Sharkey        if (t instanceof FileNotFoundException) {
3200c2d31bfa113c2848620ac05c916802410b71da1Jeff Sharkey            throw (FileNotFoundException) t;
3210c2d31bfa113c2848620ac05c916802410b71da1Jeff Sharkey        }
3220c2d31bfa113c2848620ac05c916802410b71da1Jeff Sharkey        final FileNotFoundException fnfe = new FileNotFoundException(t.getMessage());
3230c2d31bfa113c2848620ac05c916802410b71da1Jeff Sharkey        fnfe.initCause(t);
3240c2d31bfa113c2848620ac05c916802410b71da1Jeff Sharkey        throw fnfe;
3250c2d31bfa113c2848620ac05c916802410b71da1Jeff Sharkey    }
326ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey}
327