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