RootInfo.java revision c6a4cd8c0f35a7e9d126ab09924f8f1f8422182a
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
17package com.android.documentsui.model;
18
19import static com.android.documentsui.model.DocumentInfo.getCursorInt;
20import static com.android.documentsui.model.DocumentInfo.getCursorLong;
21import static com.android.documentsui.model.DocumentInfo.getCursorString;
22
23import android.content.Context;
24import android.database.Cursor;
25import android.graphics.drawable.Drawable;
26import android.os.Parcel;
27import android.os.Parcelable;
28import android.provider.DocumentsContract.Root;
29import android.text.TextUtils;
30
31import com.android.documentsui.IconUtils;
32import com.android.documentsui.R;
33
34import java.io.DataInputStream;
35import java.io.DataOutputStream;
36import java.io.IOException;
37import java.net.ProtocolException;
38import java.util.Objects;
39
40/**
41 * Representation of a {@link Root}.
42 */
43public class RootInfo implements Durable, Parcelable {
44    private static final int VERSION_INIT = 1;
45    private static final int VERSION_DROP_TYPE = 2;
46
47    // The values of these constants determine the sort order of various roots in the RootsFragment.
48    public static final int TYPE_IMAGES = 1;
49    public static final int TYPE_VIDEO = 2;
50    public static final int TYPE_AUDIO = 3;
51    public static final int TYPE_RECENTS = 4;
52    public static final int TYPE_DOWNLOADS = 5;
53    public static final int TYPE_LOCAL = 6;
54    public static final int TYPE_MTP = 7;
55    public static final int TYPE_OTHER = 8;
56
57    public String authority;
58    public String rootId;
59    public int flags;
60    public int icon;
61    public String title;
62    public String summary;
63    public String documentId;
64    public long availableBytes;
65    public String mimeTypes;
66
67    /** Derived fields that aren't persisted */
68    public String[] derivedMimeTypes;
69    public int derivedIcon;
70    public int derivedType;
71
72    public RootInfo() {
73        reset();
74    }
75
76    @Override
77    public void reset() {
78        authority = null;
79        rootId = null;
80        flags = 0;
81        icon = 0;
82        title = null;
83        summary = null;
84        documentId = null;
85        availableBytes = -1;
86        mimeTypes = null;
87
88        derivedMimeTypes = null;
89        derivedIcon = 0;
90        derivedType = 0;
91    }
92
93    @Override
94    public void read(DataInputStream in) throws IOException {
95        final int version = in.readInt();
96        switch (version) {
97            case VERSION_DROP_TYPE:
98                authority = DurableUtils.readNullableString(in);
99                rootId = DurableUtils.readNullableString(in);
100                flags = in.readInt();
101                icon = in.readInt();
102                title = DurableUtils.readNullableString(in);
103                summary = DurableUtils.readNullableString(in);
104                documentId = DurableUtils.readNullableString(in);
105                availableBytes = in.readLong();
106                mimeTypes = DurableUtils.readNullableString(in);
107                deriveFields();
108                break;
109            default:
110                throw new ProtocolException("Unknown version " + version);
111        }
112    }
113
114    @Override
115    public void write(DataOutputStream out) throws IOException {
116        out.writeInt(VERSION_DROP_TYPE);
117        DurableUtils.writeNullableString(out, authority);
118        DurableUtils.writeNullableString(out, rootId);
119        out.writeInt(flags);
120        out.writeInt(icon);
121        DurableUtils.writeNullableString(out, title);
122        DurableUtils.writeNullableString(out, summary);
123        DurableUtils.writeNullableString(out, documentId);
124        out.writeLong(availableBytes);
125        DurableUtils.writeNullableString(out, mimeTypes);
126    }
127
128    @Override
129    public int describeContents() {
130        return 0;
131    }
132
133    @Override
134    public void writeToParcel(Parcel dest, int flags) {
135        DurableUtils.writeToParcel(dest, this);
136    }
137
138    public static final Creator<RootInfo> CREATOR = new Creator<RootInfo>() {
139        @Override
140        public RootInfo createFromParcel(Parcel in) {
141            final RootInfo root = new RootInfo();
142            DurableUtils.readFromParcel(in, root);
143            return root;
144        }
145
146        @Override
147        public RootInfo[] newArray(int size) {
148            return new RootInfo[size];
149        }
150    };
151
152    public static RootInfo fromRootsCursor(String authority, Cursor cursor) {
153        final RootInfo root = new RootInfo();
154        root.authority = authority;
155        root.rootId = getCursorString(cursor, Root.COLUMN_ROOT_ID);
156        root.flags = getCursorInt(cursor, Root.COLUMN_FLAGS);
157        root.icon = getCursorInt(cursor, Root.COLUMN_ICON);
158        root.title = getCursorString(cursor, Root.COLUMN_TITLE);
159        root.summary = getCursorString(cursor, Root.COLUMN_SUMMARY);
160        root.documentId = getCursorString(cursor, Root.COLUMN_DOCUMENT_ID);
161        root.availableBytes = getCursorLong(cursor, Root.COLUMN_AVAILABLE_BYTES);
162        root.mimeTypes = getCursorString(cursor, Root.COLUMN_MIME_TYPES);
163        root.deriveFields();
164        return root;
165    }
166
167    private void deriveFields() {
168        derivedMimeTypes = (mimeTypes != null) ? mimeTypes.split("\n") : null;
169
170        // TODO: remove these special case icons
171        if (isHome()) {
172            derivedIcon = R.drawable.ic_root_home;
173            derivedType = TYPE_LOCAL;
174        } else if (isExternalStorage()) {
175            derivedIcon = R.drawable.ic_root_sdcard;
176            derivedType = TYPE_LOCAL;
177        } else if (isDownloads()) {
178            derivedIcon = R.drawable.ic_root_download;
179            derivedType = TYPE_DOWNLOADS;
180        } else if (isImages()) {
181            derivedIcon = R.drawable.ic_doc_image;
182            derivedType = TYPE_IMAGES;
183        } else if (isVideos()) {
184            derivedIcon = R.drawable.ic_doc_video;
185            derivedType = TYPE_VIDEO;
186        } else if (isAudio()) {
187            derivedIcon = R.drawable.ic_doc_audio;
188            derivedType = TYPE_AUDIO;
189        } else if (isRecents()) {
190            derivedType = TYPE_RECENTS;
191        } else if (isMtp()) {
192            derivedType = TYPE_MTP;
193        } else {
194            derivedType = TYPE_OTHER;
195        }
196    }
197
198    public boolean isRecents() {
199        return authority == null && rootId == null;
200    }
201
202    public boolean isHome() {
203        // Note that "home" is the expected root id for the auto-created
204        // user home directory on external storage. The "home" value should
205        // match ExternalStorageProvider.ROOT_ID_HOME.
206        return isExternalStorage() && "home".equals(rootId);
207    }
208
209    public boolean isExternalStorage() {
210        return "com.android.externalstorage.documents".equals(authority);
211    }
212
213    public boolean isDownloads() {
214        return "com.android.providers.downloads.documents".equals(authority);
215    }
216
217    public boolean isImages() {
218        return "com.android.providers.media.documents".equals(authority)
219                && "images_root".equals(rootId);
220    }
221
222    public boolean isVideos() {
223        return "com.android.providers.media.documents".equals(authority)
224                && "videos_root".equals(rootId);
225    }
226
227    public boolean isAudio() {
228        return "com.android.providers.media.documents".equals(authority)
229                && "audio_root".equals(rootId);
230    }
231
232    public boolean isMtp() {
233        return "com.android.mtp.documents".equals(authority);
234    }
235
236    public boolean isLibrary() {
237        return derivedType == TYPE_IMAGES || derivedType == TYPE_VIDEO || derivedType == TYPE_AUDIO
238                || derivedType == TYPE_RECENTS || derivedType == TYPE_DOWNLOADS;
239    }
240
241    @Override
242    public String toString() {
243        return "Root{authority=" + authority + ", rootId=" + rootId + ", title=" + title + "}";
244    }
245
246    public Drawable loadIcon(Context context) {
247        if (derivedIcon != 0) {
248            return context.getDrawable(derivedIcon);
249        } else {
250            return IconUtils.loadPackageIcon(context, authority, icon);
251        }
252    }
253
254    public Drawable loadDrawerIcon(Context context) {
255        if (derivedIcon != 0) {
256            return IconUtils.applyTintColor(context, derivedIcon, R.color.item_root_icon);
257        } else {
258            return IconUtils.loadPackageIcon(context, authority, icon);
259        }
260    }
261
262    public Drawable loadToolbarIcon(Context context) {
263        if (derivedIcon != 0) {
264            return IconUtils.applyTintAttr(context, derivedIcon,
265                    android.R.attr.colorControlNormal);
266        } else {
267            return IconUtils.loadPackageIcon(context, authority, icon);
268        }
269    }
270
271    @Override
272    public boolean equals(Object o) {
273        if (o instanceof RootInfo) {
274            final RootInfo root = (RootInfo) o;
275            return Objects.equals(authority, root.authority) && Objects.equals(rootId, root.rootId);
276        } else {
277            return false;
278        }
279    }
280
281    @Override
282    public int hashCode() {
283        return Objects.hash(authority, rootId);
284    }
285
286    public String getDirectoryString() {
287        return !TextUtils.isEmpty(summary) ? summary : title;
288    }
289}
290