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[] derivedMimeTypes;
59     public int derivedIcon;
60 
RootInfo()61     public RootInfo() {
62         reset();
63     }
64 
65     @Override
reset()66     public void reset() {
67         authority = null;
68         rootId = null;
69         flags = 0;
70         icon = 0;
71         title = null;
72         summary = null;
73         documentId = null;
74         availableBytes = -1;
75         mimeTypes = null;
76 
77         derivedMimeTypes = null;
78         derivedIcon = 0;
79     }
80 
81     @Override
read(DataInputStream in)82     public void read(DataInputStream in) throws IOException {
83         final int version = in.readInt();
84         switch (version) {
85             case VERSION_DROP_TYPE:
86                 authority = DurableUtils.readNullableString(in);
87                 rootId = DurableUtils.readNullableString(in);
88                 flags = in.readInt();
89                 icon = in.readInt();
90                 title = DurableUtils.readNullableString(in);
91                 summary = DurableUtils.readNullableString(in);
92                 documentId = DurableUtils.readNullableString(in);
93                 availableBytes = in.readLong();
94                 mimeTypes = DurableUtils.readNullableString(in);
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_DROP_TYPE);
105         DurableUtils.writeNullableString(out, authority);
106         DurableUtils.writeNullableString(out, rootId);
107         out.writeInt(flags);
108         out.writeInt(icon);
109         DurableUtils.writeNullableString(out, title);
110         DurableUtils.writeNullableString(out, summary);
111         DurableUtils.writeNullableString(out, documentId);
112         out.writeLong(availableBytes);
113         DurableUtils.writeNullableString(out, mimeTypes);
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<RootInfo> CREATOR = new Creator<RootInfo>() {
127         @Override
128         public RootInfo createFromParcel(Parcel in) {
129             final RootInfo root = new RootInfo();
130             DurableUtils.readFromParcel(in, root);
131             return root;
132         }
133 
134         @Override
135         public RootInfo[] newArray(int size) {
136             return new RootInfo[size];
137         }
138     };
139 
fromRootsCursor(String authority, Cursor cursor)140     public static RootInfo fromRootsCursor(String authority, Cursor cursor) {
141         final RootInfo root = new RootInfo();
142         root.authority = authority;
143         root.rootId = getCursorString(cursor, Root.COLUMN_ROOT_ID);
144         root.flags = getCursorInt(cursor, Root.COLUMN_FLAGS);
145         root.icon = getCursorInt(cursor, Root.COLUMN_ICON);
146         root.title = getCursorString(cursor, Root.COLUMN_TITLE);
147         root.summary = getCursorString(cursor, Root.COLUMN_SUMMARY);
148         root.documentId = getCursorString(cursor, Root.COLUMN_DOCUMENT_ID);
149         root.availableBytes = getCursorLong(cursor, Root.COLUMN_AVAILABLE_BYTES);
150         root.mimeTypes = getCursorString(cursor, Root.COLUMN_MIME_TYPES);
151         root.deriveFields();
152         return root;
153     }
154 
deriveFields()155     private void deriveFields() {
156         derivedMimeTypes = (mimeTypes != null) ? mimeTypes.split("\n") : null;
157 
158         // TODO: remove these special case icons
159         if (isExternalStorage()) {
160             derivedIcon = R.drawable.ic_root_sdcard;
161         } else if (isDownloads()) {
162             derivedIcon = R.drawable.ic_root_download;
163         } else if (isImages()) {
164             derivedIcon = R.drawable.ic_doc_image;
165         } else if (isVideos()) {
166             derivedIcon = R.drawable.ic_doc_video;
167         } else if (isAudio()) {
168             derivedIcon = R.drawable.ic_doc_audio;
169         }
170     }
171 
isRecents()172     public boolean isRecents() {
173         return authority == null && rootId == null;
174     }
175 
isExternalStorage()176     public boolean isExternalStorage() {
177         return "com.android.externalstorage.documents".equals(authority);
178     }
179 
isDownloads()180     public boolean isDownloads() {
181         return "com.android.providers.downloads.documents".equals(authority);
182     }
183 
isImages()184     public boolean isImages() {
185         return "com.android.providers.media.documents".equals(authority)
186                 && "images_root".equals(rootId);
187     }
188 
isVideos()189     public boolean isVideos() {
190         return "com.android.providers.media.documents".equals(authority)
191                 && "videos_root".equals(rootId);
192     }
193 
isAudio()194     public boolean isAudio() {
195         return "com.android.providers.media.documents".equals(authority)
196                 && "audio_root".equals(rootId);
197     }
198 
199     @Override
toString()200     public String toString() {
201         return "Root{authority=" + authority + ", rootId=" + rootId + ", title=" + title + "}";
202     }
203 
loadIcon(Context context)204     public Drawable loadIcon(Context context) {
205         if (derivedIcon != 0) {
206             return context.getDrawable(derivedIcon);
207         } else {
208             return IconUtils.loadPackageIcon(context, authority, icon);
209         }
210     }
211 
loadDrawerIcon(Context context)212     public Drawable loadDrawerIcon(Context context) {
213         if (derivedIcon != 0) {
214             return IconUtils.applyTintColor(context, derivedIcon, R.color.item_root_icon);
215         } else {
216             return IconUtils.loadPackageIcon(context, authority, icon);
217         }
218     }
219 
loadGridIcon(Context context)220     public Drawable loadGridIcon(Context context) {
221         if (derivedIcon != 0) {
222             return IconUtils.applyTintAttr(context, derivedIcon,
223                     android.R.attr.textColorPrimaryInverse);
224         } else {
225             return IconUtils.loadPackageIcon(context, authority, icon);
226         }
227     }
228 
loadToolbarIcon(Context context)229     public Drawable loadToolbarIcon(Context context) {
230         if (derivedIcon != 0) {
231             return IconUtils.applyTintAttr(context, derivedIcon,
232                     android.R.attr.colorControlNormal);
233         } else {
234             return IconUtils.loadPackageIcon(context, authority, icon);
235         }
236     }
237 
238     @Override
equals(Object o)239     public boolean equals(Object o) {
240         if (o instanceof RootInfo) {
241             final RootInfo root = (RootInfo) o;
242             return Objects.equals(authority, root.authority) && Objects.equals(rootId, root.rootId);
243         } else {
244             return false;
245         }
246     }
247 
248     @Override
hashCode()249     public int hashCode() {
250         return Objects.hash(authority, rootId);
251     }
252 
getDirectoryString()253     public String getDirectoryString() {
254         return !TextUtils.isEmpty(summary) ? summary : title;
255     }
256 }
257