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