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