1 /* 2 * Copyright (C) 2016 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.internal.util; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.content.ContentResolver.MimeTypeInfo; 22 import android.content.res.Resources; 23 import android.graphics.drawable.Icon; 24 import android.text.TextUtils; 25 import android.util.ArrayMap; 26 27 import com.android.internal.R; 28 import com.android.internal.annotations.GuardedBy; 29 30 import libcore.content.type.MimeMap; 31 32 import java.util.Locale; 33 import java.util.Objects; 34 35 public class MimeIconUtils { 36 @GuardedBy("sCache") 37 private static final ArrayMap<String, MimeTypeInfo> sCache = new ArrayMap<>(); 38 buildTypeInfo(String mimeType, int iconId, int labelId, int extLabelId)39 private static MimeTypeInfo buildTypeInfo(String mimeType, int iconId, 40 int labelId, int extLabelId) { 41 final Resources res = Resources.getSystem(); 42 43 // If this MIME type has an extension, customize the label 44 final CharSequence label; 45 final String ext = MimeMap.getDefault().guessExtensionFromMimeType(mimeType); 46 if (!TextUtils.isEmpty(ext) && extLabelId != -1) { 47 label = res.getString(extLabelId, ext.toUpperCase(Locale.US)); 48 } else { 49 label = res.getString(labelId); 50 } 51 52 return new MimeTypeInfo(Icon.createWithResource(res, iconId), label, label); 53 } 54 buildTypeInfo(@onNull String mimeType)55 private static @Nullable MimeTypeInfo buildTypeInfo(@NonNull String mimeType) { 56 switch (mimeType) { 57 case "inode/directory": 58 case "vnd.android.document/directory": 59 return buildTypeInfo(mimeType, R.drawable.ic_doc_folder, 60 R.string.mime_type_folder, -1); 61 62 case "application/vnd.android.package-archive": 63 return buildTypeInfo(mimeType, R.drawable.ic_doc_apk, 64 R.string.mime_type_apk, -1); 65 66 case "application/pgp-keys": 67 case "application/pgp-signature": 68 case "application/x-pkcs12": 69 case "application/x-pkcs7-certreqresp": 70 case "application/x-pkcs7-crl": 71 case "application/x-x509-ca-cert": 72 case "application/x-x509-user-cert": 73 case "application/x-pkcs7-certificates": 74 case "application/x-pkcs7-mime": 75 case "application/x-pkcs7-signature": 76 return buildTypeInfo(mimeType, R.drawable.ic_doc_certificate, 77 R.string.mime_type_generic, R.string.mime_type_generic_ext); 78 79 case "application/rdf+xml": 80 case "application/rss+xml": 81 case "application/x-object": 82 case "application/xhtml+xml": 83 case "text/css": 84 case "text/html": 85 case "text/xml": 86 case "text/x-c++hdr": 87 case "text/x-c++src": 88 case "text/x-chdr": 89 case "text/x-csrc": 90 case "text/x-dsrc": 91 case "text/x-csh": 92 case "text/x-haskell": 93 case "text/x-java": 94 case "text/x-literate-haskell": 95 case "text/x-pascal": 96 case "text/x-tcl": 97 case "text/x-tex": 98 case "application/x-latex": 99 case "application/x-texinfo": 100 case "application/atom+xml": 101 case "application/ecmascript": 102 case "application/json": 103 case "application/javascript": 104 case "application/xml": 105 case "text/javascript": 106 case "application/x-javascript": 107 return buildTypeInfo(mimeType, R.drawable.ic_doc_codes, 108 R.string.mime_type_document, R.string.mime_type_document_ext); 109 110 case "application/mac-binhex40": 111 case "application/rar": 112 case "application/zip": 113 case "application/x-apple-diskimage": 114 case "application/x-debian-package": 115 case "application/x-gtar": 116 case "application/x-iso9660-image": 117 case "application/x-lha": 118 case "application/x-lzh": 119 case "application/x-lzx": 120 case "application/x-stuffit": 121 case "application/x-tar": 122 case "application/x-webarchive": 123 case "application/x-webarchive-xml": 124 case "application/gzip": 125 case "application/x-7z-compressed": 126 case "application/x-deb": 127 case "application/x-rar-compressed": 128 return buildTypeInfo(mimeType, R.drawable.ic_doc_compressed, 129 R.string.mime_type_compressed, R.string.mime_type_compressed_ext); 130 131 case "text/x-vcard": 132 case "text/vcard": 133 return buildTypeInfo(mimeType, R.drawable.ic_doc_contact, 134 R.string.mime_type_generic, R.string.mime_type_generic_ext); 135 136 case "text/calendar": 137 case "text/x-vcalendar": 138 return buildTypeInfo(mimeType, R.drawable.ic_doc_event, 139 R.string.mime_type_generic, R.string.mime_type_generic_ext); 140 141 case "application/x-font": 142 case "application/font-woff": 143 case "application/x-font-woff": 144 case "application/x-font-ttf": 145 return buildTypeInfo(mimeType, R.drawable.ic_doc_font, 146 R.string.mime_type_generic, R.string.mime_type_generic_ext); 147 148 case "application/vnd.oasis.opendocument.graphics": 149 case "application/vnd.oasis.opendocument.graphics-template": 150 case "application/vnd.oasis.opendocument.image": 151 case "application/vnd.stardivision.draw": 152 case "application/vnd.sun.xml.draw": 153 case "application/vnd.sun.xml.draw.template": 154 case "application/vnd.google-apps.drawing": 155 return buildTypeInfo(mimeType, R.drawable.ic_doc_image, 156 R.string.mime_type_image, R.string.mime_type_image_ext); 157 158 case "application/pdf": 159 return buildTypeInfo(mimeType, R.drawable.ic_doc_pdf, 160 R.string.mime_type_document, R.string.mime_type_document_ext); 161 162 case "application/vnd.stardivision.impress": 163 case "application/vnd.sun.xml.impress": 164 case "application/vnd.sun.xml.impress.template": 165 case "application/x-kpresenter": 166 case "application/vnd.oasis.opendocument.presentation": 167 case "application/vnd.google-apps.presentation": 168 return buildTypeInfo(mimeType, R.drawable.ic_doc_presentation, 169 R.string.mime_type_presentation, R.string.mime_type_presentation_ext); 170 171 case "application/vnd.oasis.opendocument.spreadsheet": 172 case "application/vnd.oasis.opendocument.spreadsheet-template": 173 case "application/vnd.stardivision.calc": 174 case "application/vnd.sun.xml.calc": 175 case "application/vnd.sun.xml.calc.template": 176 case "application/x-kspread": 177 case "application/vnd.google-apps.spreadsheet": 178 return buildTypeInfo(mimeType, R.drawable.ic_doc_spreadsheet, 179 R.string.mime_type_spreadsheet, R.string.mime_type_spreadsheet_ext); 180 181 case "application/vnd.oasis.opendocument.text": 182 case "application/vnd.oasis.opendocument.text-master": 183 case "application/vnd.oasis.opendocument.text-template": 184 case "application/vnd.oasis.opendocument.text-web": 185 case "application/vnd.stardivision.writer": 186 case "application/vnd.stardivision.writer-global": 187 case "application/vnd.sun.xml.writer": 188 case "application/vnd.sun.xml.writer.global": 189 case "application/vnd.sun.xml.writer.template": 190 case "application/x-abiword": 191 case "application/x-kword": 192 case "application/vnd.google-apps.document": 193 return buildTypeInfo(mimeType, R.drawable.ic_doc_document, 194 R.string.mime_type_document, R.string.mime_type_document_ext); 195 196 case "application/x-quicktimeplayer": 197 case "application/x-shockwave-flash": 198 return buildTypeInfo(mimeType, R.drawable.ic_doc_video, 199 R.string.mime_type_video, R.string.mime_type_video_ext); 200 201 case "application/msword": 202 case "application/vnd.openxmlformats-officedocument.wordprocessingml.document": 203 case "application/vnd.openxmlformats-officedocument.wordprocessingml.template": 204 return buildTypeInfo(mimeType, R.drawable.ic_doc_word, 205 R.string.mime_type_document, R.string.mime_type_document_ext); 206 207 case "application/vnd.ms-excel": 208 case "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": 209 case "application/vnd.openxmlformats-officedocument.spreadsheetml.template": 210 return buildTypeInfo(mimeType, R.drawable.ic_doc_excel, 211 R.string.mime_type_spreadsheet, R.string.mime_type_spreadsheet_ext); 212 213 case "application/vnd.ms-powerpoint": 214 case "application/vnd.openxmlformats-officedocument.presentationml.presentation": 215 case "application/vnd.openxmlformats-officedocument.presentationml.template": 216 case "application/vnd.openxmlformats-officedocument.presentationml.slideshow": 217 return buildTypeInfo(mimeType, R.drawable.ic_doc_powerpoint, 218 R.string.mime_type_presentation, R.string.mime_type_presentation_ext); 219 220 default: 221 return buildGenericTypeInfo(mimeType); 222 } 223 } 224 buildGenericTypeInfo(@onNull String mimeType)225 private static @Nullable MimeTypeInfo buildGenericTypeInfo(@NonNull String mimeType) { 226 // Look for partial matches 227 if (mimeType.startsWith("audio/")) { 228 return buildTypeInfo(mimeType, R.drawable.ic_doc_audio, 229 R.string.mime_type_audio, R.string.mime_type_audio_ext); 230 } else if (mimeType.startsWith("video/")) { 231 return buildTypeInfo(mimeType, R.drawable.ic_doc_video, 232 R.string.mime_type_video, R.string.mime_type_video_ext); 233 } else if (mimeType.startsWith("image/")) { 234 return buildTypeInfo(mimeType, R.drawable.ic_doc_image, 235 R.string.mime_type_image, R.string.mime_type_image_ext); 236 } else if (mimeType.startsWith("text/")) { 237 return buildTypeInfo(mimeType, R.drawable.ic_doc_text, 238 R.string.mime_type_document, R.string.mime_type_document_ext); 239 } 240 241 // As one last-ditch effort, try "bouncing" the MIME type through its 242 // default extension. This handles cases like "application/x-flac" to 243 // ".flac" to "audio/flac". 244 MimeMap mimeMap = MimeMap.getDefault(); 245 final String bouncedMimeType = mimeMap 246 .guessMimeTypeFromExtension(mimeMap.guessExtensionFromMimeType(mimeType)); 247 if (bouncedMimeType != null && !Objects.equals(mimeType, bouncedMimeType)) { 248 return buildTypeInfo(bouncedMimeType); 249 } 250 251 // Worst case, return a generic file 252 return buildTypeInfo(mimeType, R.drawable.ic_doc_generic, 253 R.string.mime_type_generic, R.string.mime_type_generic_ext); 254 } 255 getTypeInfo(@onNull String mimeType)256 public static @NonNull MimeTypeInfo getTypeInfo(@NonNull String mimeType) { 257 // Normalize MIME type 258 mimeType = mimeType.toLowerCase(Locale.US); 259 260 synchronized (sCache) { 261 MimeTypeInfo res = sCache.get(mimeType); 262 if (res == null) { 263 res = buildTypeInfo(mimeType); 264 sCache.put(mimeType, res); 265 } 266 return res; 267 } 268 } 269 } 270