FileCollector.java revision 1009c08f8e11bb050ce395e8f6a0ed318b1902a1
1/* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy of 6 * the License at 7 * 8 * http://www.apache.org/licenses/LICENSE2.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, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations under 14 * the License. 15 */ 16 17package com.android.server.storage; 18 19import android.annotation.IntDef; 20import android.content.Context; 21import android.content.pm.PackageManager; 22import android.os.storage.StorageManager; 23import android.os.storage.VolumeInfo; 24import android.util.ArrayMap; 25 26import java.io.File; 27import java.lang.annotation.Retention; 28import java.lang.annotation.RetentionPolicy; 29import java.util.Map; 30 31/** 32 * FileCollector walks over a directory and categorizes storage usage by their type. 33 */ 34public class FileCollector { 35 private static final int UNRECOGNIZED = -1; 36 private static final int IMAGES = 0; 37 private static final int VIDEO = 1; 38 private static final int AUDIO = 2; 39 @Retention(RetentionPolicy.SOURCE) 40 @IntDef({ 41 UNRECOGNIZED, 42 IMAGES, 43 VIDEO, 44 AUDIO }) 45 private @interface FileTypes {} 46 47 48 private static final Map<String, Integer> EXTENSION_MAP = new ArrayMap<String, Integer>(); 49 static { 50 // Audio 51 EXTENSION_MAP.put("aac", AUDIO); 52 EXTENSION_MAP.put("amr", AUDIO); 53 EXTENSION_MAP.put("awb", AUDIO); 54 EXTENSION_MAP.put("snd", AUDIO); 55 EXTENSION_MAP.put("flac", AUDIO); 56 EXTENSION_MAP.put("mp3", AUDIO); 57 EXTENSION_MAP.put("mpga", AUDIO); 58 EXTENSION_MAP.put("mpega", AUDIO); 59 EXTENSION_MAP.put("mp2", AUDIO); 60 EXTENSION_MAP.put("m4a", AUDIO); 61 EXTENSION_MAP.put("aif", AUDIO); 62 EXTENSION_MAP.put("aiff", AUDIO); 63 EXTENSION_MAP.put("aifc", AUDIO); 64 EXTENSION_MAP.put("gsm", AUDIO); 65 EXTENSION_MAP.put("mka", AUDIO); 66 EXTENSION_MAP.put("m3u", AUDIO); 67 EXTENSION_MAP.put("wma", AUDIO); 68 EXTENSION_MAP.put("wax", AUDIO); 69 EXTENSION_MAP.put("ra", AUDIO); 70 EXTENSION_MAP.put("rm", AUDIO); 71 EXTENSION_MAP.put("ram", AUDIO); 72 EXTENSION_MAP.put("pls", AUDIO); 73 EXTENSION_MAP.put("sd2", AUDIO); 74 EXTENSION_MAP.put("wav", AUDIO); 75 EXTENSION_MAP.put("ogg", AUDIO); 76 EXTENSION_MAP.put("oga", AUDIO); 77 // Video 78 EXTENSION_MAP.put("3gpp", VIDEO); 79 EXTENSION_MAP.put("3gp", VIDEO); 80 EXTENSION_MAP.put("3gpp2", VIDEO); 81 EXTENSION_MAP.put("3g2", VIDEO); 82 EXTENSION_MAP.put("avi", VIDEO); 83 EXTENSION_MAP.put("dl", VIDEO); 84 EXTENSION_MAP.put("dif", VIDEO); 85 EXTENSION_MAP.put("dv", VIDEO); 86 EXTENSION_MAP.put("fli", VIDEO); 87 EXTENSION_MAP.put("m4v", VIDEO); 88 EXTENSION_MAP.put("ts", VIDEO); 89 EXTENSION_MAP.put("mpeg", VIDEO); 90 EXTENSION_MAP.put("mpg", VIDEO); 91 EXTENSION_MAP.put("mpe", VIDEO); 92 EXTENSION_MAP.put("mp4", VIDEO); 93 EXTENSION_MAP.put("vob", VIDEO); 94 EXTENSION_MAP.put("qt", VIDEO); 95 EXTENSION_MAP.put("mov", VIDEO); 96 EXTENSION_MAP.put("mxu", VIDEO); 97 EXTENSION_MAP.put("webm", VIDEO); 98 EXTENSION_MAP.put("lsf", VIDEO); 99 EXTENSION_MAP.put("lsx", VIDEO); 100 EXTENSION_MAP.put("mkv", VIDEO); 101 EXTENSION_MAP.put("mng", VIDEO); 102 EXTENSION_MAP.put("asf", VIDEO); 103 EXTENSION_MAP.put("asx", VIDEO); 104 EXTENSION_MAP.put("wm", VIDEO); 105 EXTENSION_MAP.put("wmv", VIDEO); 106 EXTENSION_MAP.put("wmx", VIDEO); 107 EXTENSION_MAP.put("wvx", VIDEO); 108 EXTENSION_MAP.put("movie", VIDEO); 109 EXTENSION_MAP.put("wrf", VIDEO); 110 // Images 111 EXTENSION_MAP.put("bmp", IMAGES); 112 EXTENSION_MAP.put("gif", IMAGES); 113 EXTENSION_MAP.put("jpg", IMAGES); 114 EXTENSION_MAP.put("jpeg", IMAGES); 115 EXTENSION_MAP.put("jpe", IMAGES); 116 EXTENSION_MAP.put("pcx", IMAGES); 117 EXTENSION_MAP.put("png", IMAGES); 118 EXTENSION_MAP.put("svg", IMAGES); 119 EXTENSION_MAP.put("svgz", IMAGES); 120 EXTENSION_MAP.put("tiff", IMAGES); 121 EXTENSION_MAP.put("tif", IMAGES); 122 EXTENSION_MAP.put("wbmp", IMAGES); 123 EXTENSION_MAP.put("webp", IMAGES); 124 EXTENSION_MAP.put("dng", IMAGES); 125 EXTENSION_MAP.put("cr2", IMAGES); 126 EXTENSION_MAP.put("ras", IMAGES); 127 EXTENSION_MAP.put("art", IMAGES); 128 EXTENSION_MAP.put("jng", IMAGES); 129 EXTENSION_MAP.put("nef", IMAGES); 130 EXTENSION_MAP.put("nrw", IMAGES); 131 EXTENSION_MAP.put("orf", IMAGES); 132 EXTENSION_MAP.put("rw2", IMAGES); 133 EXTENSION_MAP.put("pef", IMAGES); 134 EXTENSION_MAP.put("psd", IMAGES); 135 EXTENSION_MAP.put("pnm", IMAGES); 136 EXTENSION_MAP.put("pbm", IMAGES); 137 EXTENSION_MAP.put("pgm", IMAGES); 138 EXTENSION_MAP.put("ppm", IMAGES); 139 EXTENSION_MAP.put("srw", IMAGES); 140 EXTENSION_MAP.put("arw", IMAGES); 141 EXTENSION_MAP.put("rgb", IMAGES); 142 EXTENSION_MAP.put("xbm", IMAGES); 143 EXTENSION_MAP.put("xpm", IMAGES); 144 EXTENSION_MAP.put("xwd", IMAGES); 145 } 146 147 /** 148 * Returns the file categorization measurement result. 149 * @param path Directory to collect and categorize storage in. 150 */ 151 public static MeasurementResult getMeasurementResult(File path) { 152 return collectFiles(StorageManager.maybeTranslateEmulatedPathToInternal(path), 153 new MeasurementResult()); 154 } 155 156 /** 157 * Returns the size of a system for a given context. This is done by finding the difference 158 * between the shared data and the total primary storage size. 159 * @param context Context to use to get storage information. 160 */ 161 public static long getSystemSize(Context context) { 162 PackageManager pm = context.getPackageManager(); 163 VolumeInfo primaryVolume = pm.getPrimaryStorageCurrentVolume(); 164 165 StorageManager sm = context.getSystemService(StorageManager.class); 166 VolumeInfo shared = sm.findEmulatedForPrivate(primaryVolume); 167 if (shared == null) { 168 return 0; 169 } 170 171 final long sharedDataSize = shared.getPath().getTotalSpace(); 172 long systemSize = sm.getPrimaryStorageSize() - sharedDataSize; 173 174 // This case is not exceptional -- we just fallback to the shared data volume in this case. 175 if (systemSize <= 0) { 176 return 0; 177 } 178 179 return systemSize; 180 } 181 182 private static MeasurementResult collectFiles(File file, MeasurementResult result) { 183 File[] files = file.listFiles(); 184 185 if (files == null) { 186 return result; 187 } 188 189 for (File f : files) { 190 if (f.isDirectory()) { 191 try { 192 collectFiles(f, result); 193 } catch (StackOverflowError e) { 194 return result; 195 } 196 } else { 197 handleFile(result, f); 198 } 199 } 200 201 return result; 202 } 203 204 private static void handleFile(MeasurementResult result, File f) { 205 long fileSize = f.length(); 206 int fileType = EXTENSION_MAP.getOrDefault(getExtensionForFile(f), UNRECOGNIZED); 207 switch (fileType) { 208 case AUDIO: 209 result.audioSize += fileSize; 210 break; 211 case VIDEO: 212 result.videosSize += fileSize; 213 break; 214 case IMAGES: 215 result.imagesSize += fileSize; 216 break; 217 default: 218 result.miscSize += fileSize; 219 } 220 } 221 222 private static String getExtensionForFile(File file) { 223 String fileName = file.getName(); 224 int index = fileName.lastIndexOf('.'); 225 if (index == -1) { 226 return ""; 227 } 228 return fileName.substring(index + 1).toLowerCase(); 229 } 230 231 /** 232 * MeasurementResult contains a storage categorization result. 233 */ 234 public static class MeasurementResult { 235 public long imagesSize; 236 public long videosSize; 237 public long miscSize; 238 public long audioSize; 239 240 /** 241 * Sums up the storage taken by all of the categorizable sizes in the measurement. 242 */ 243 public long totalAccountedSize() { 244 return imagesSize + videosSize + miscSize + audioSize; 245 } 246 } 247} 248