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