13c7febdbd86070337810d1ff741d35430707726aDaniel Nishi/* 23c7febdbd86070337810d1ff741d35430707726aDaniel Nishi * Copyright (C) 2016 The Android Open Source Project 33c7febdbd86070337810d1ff741d35430707726aDaniel Nishi * 43c7febdbd86070337810d1ff741d35430707726aDaniel Nishi * Licensed under the Apache License, Version 2.0 (the "License"); you may not 53c7febdbd86070337810d1ff741d35430707726aDaniel Nishi * use this file except in compliance with the License. You may obtain a copy of 63c7febdbd86070337810d1ff741d35430707726aDaniel Nishi * the License at 73c7febdbd86070337810d1ff741d35430707726aDaniel Nishi * 83c7febdbd86070337810d1ff741d35430707726aDaniel Nishi * http://www.apache.org/licenses/LICENSE2.0 93c7febdbd86070337810d1ff741d35430707726aDaniel Nishi * 103c7febdbd86070337810d1ff741d35430707726aDaniel Nishi * Unless required by applicable law or agreed to in writing, software 113c7febdbd86070337810d1ff741d35430707726aDaniel Nishi * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 123c7febdbd86070337810d1ff741d35430707726aDaniel Nishi * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 133c7febdbd86070337810d1ff741d35430707726aDaniel Nishi * License for the specific language governing permissions and limitations under 143c7febdbd86070337810d1ff741d35430707726aDaniel Nishi * the License. 153c7febdbd86070337810d1ff741d35430707726aDaniel Nishi */ 163c7febdbd86070337810d1ff741d35430707726aDaniel Nishi 173c7febdbd86070337810d1ff741d35430707726aDaniel Nishipackage com.android.server.storage; 183c7febdbd86070337810d1ff741d35430707726aDaniel Nishi 193c7febdbd86070337810d1ff741d35430707726aDaniel Nishiimport android.annotation.IntDef; 205d230dc202cb03185652e12b3024ceea1132dd4dDaniel Nishiimport android.app.usage.ExternalStorageStats; 215d230dc202cb03185652e12b3024ceea1132dd4dDaniel Nishiimport android.app.usage.StorageStatsManager; 2277a78c6f4412dccc58075685ad77f3e41d85f2e4Daniel Nishiimport android.content.Context; 2377a78c6f4412dccc58075685ad77f3e41d85f2e4Daniel Nishiimport android.content.pm.PackageManager; 245d230dc202cb03185652e12b3024ceea1132dd4dDaniel Nishiimport android.os.UserHandle; 253c7febdbd86070337810d1ff741d35430707726aDaniel Nishiimport android.os.storage.StorageManager; 2677a78c6f4412dccc58075685ad77f3e41d85f2e4Daniel Nishiimport android.os.storage.VolumeInfo; 273c7febdbd86070337810d1ff741d35430707726aDaniel Nishiimport android.util.ArrayMap; 283c7febdbd86070337810d1ff741d35430707726aDaniel Nishi 293c7febdbd86070337810d1ff741d35430707726aDaniel Nishiimport java.io.File; 305d230dc202cb03185652e12b3024ceea1132dd4dDaniel Nishiimport java.io.IOException; 313c7febdbd86070337810d1ff741d35430707726aDaniel Nishiimport java.lang.annotation.Retention; 323c7febdbd86070337810d1ff741d35430707726aDaniel Nishiimport java.lang.annotation.RetentionPolicy; 331009c08f8e11bb050ce395e8f6a0ed318b1902a1Jeff Sharkeyimport java.util.Map; 343c7febdbd86070337810d1ff741d35430707726aDaniel Nishi 353c7febdbd86070337810d1ff741d35430707726aDaniel Nishi/** 363c7febdbd86070337810d1ff741d35430707726aDaniel Nishi * FileCollector walks over a directory and categorizes storage usage by their type. 373c7febdbd86070337810d1ff741d35430707726aDaniel Nishi */ 383c7febdbd86070337810d1ff741d35430707726aDaniel Nishipublic class FileCollector { 393c7febdbd86070337810d1ff741d35430707726aDaniel Nishi private static final int UNRECOGNIZED = -1; 403c7febdbd86070337810d1ff741d35430707726aDaniel Nishi private static final int IMAGES = 0; 413c7febdbd86070337810d1ff741d35430707726aDaniel Nishi private static final int VIDEO = 1; 423c7febdbd86070337810d1ff741d35430707726aDaniel Nishi private static final int AUDIO = 2; 433c7febdbd86070337810d1ff741d35430707726aDaniel Nishi @Retention(RetentionPolicy.SOURCE) 443c7febdbd86070337810d1ff741d35430707726aDaniel Nishi @IntDef({ 453c7febdbd86070337810d1ff741d35430707726aDaniel Nishi UNRECOGNIZED, 463c7febdbd86070337810d1ff741d35430707726aDaniel Nishi IMAGES, 473c7febdbd86070337810d1ff741d35430707726aDaniel Nishi VIDEO, 483c7febdbd86070337810d1ff741d35430707726aDaniel Nishi AUDIO }) 493c7febdbd86070337810d1ff741d35430707726aDaniel Nishi private @interface FileTypes {} 503c7febdbd86070337810d1ff741d35430707726aDaniel Nishi 511009c08f8e11bb050ce395e8f6a0ed318b1902a1Jeff Sharkey 521009c08f8e11bb050ce395e8f6a0ed318b1902a1Jeff Sharkey private static final Map<String, Integer> EXTENSION_MAP = new ArrayMap<String, Integer>(); 533c7febdbd86070337810d1ff741d35430707726aDaniel Nishi static { 543c7febdbd86070337810d1ff741d35430707726aDaniel Nishi // Audio 553c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("aac", AUDIO); 563c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("amr", AUDIO); 573c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("awb", AUDIO); 583c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("snd", AUDIO); 593c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("flac", AUDIO); 603c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("mp3", AUDIO); 613c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("mpga", AUDIO); 623c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("mpega", AUDIO); 633c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("mp2", AUDIO); 643c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("m4a", AUDIO); 653c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("aif", AUDIO); 663c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("aiff", AUDIO); 673c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("aifc", AUDIO); 683c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("gsm", AUDIO); 693c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("mka", AUDIO); 703c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("m3u", AUDIO); 713c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("wma", AUDIO); 723c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("wax", AUDIO); 733c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("ra", AUDIO); 743c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("rm", AUDIO); 753c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("ram", AUDIO); 763c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("pls", AUDIO); 773c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("sd2", AUDIO); 783c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("wav", AUDIO); 793c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("ogg", AUDIO); 803c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("oga", AUDIO); 813c7febdbd86070337810d1ff741d35430707726aDaniel Nishi // Video 823c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("3gpp", VIDEO); 833c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("3gp", VIDEO); 843c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("3gpp2", VIDEO); 853c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("3g2", VIDEO); 863c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("avi", VIDEO); 873c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("dl", VIDEO); 883c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("dif", VIDEO); 893c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("dv", VIDEO); 903c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("fli", VIDEO); 913c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("m4v", VIDEO); 923c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("ts", VIDEO); 933c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("mpeg", VIDEO); 943c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("mpg", VIDEO); 953c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("mpe", VIDEO); 963c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("mp4", VIDEO); 973c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("vob", VIDEO); 983c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("qt", VIDEO); 993c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("mov", VIDEO); 1003c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("mxu", VIDEO); 1013c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("webm", VIDEO); 1023c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("lsf", VIDEO); 1033c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("lsx", VIDEO); 1043c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("mkv", VIDEO); 1053c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("mng", VIDEO); 1063c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("asf", VIDEO); 1073c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("asx", VIDEO); 1083c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("wm", VIDEO); 1093c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("wmv", VIDEO); 1103c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("wmx", VIDEO); 1113c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("wvx", VIDEO); 1123c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("movie", VIDEO); 1133c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("wrf", VIDEO); 1143c7febdbd86070337810d1ff741d35430707726aDaniel Nishi // Images 1153c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("bmp", IMAGES); 1163c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("gif", IMAGES); 1173c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("jpg", IMAGES); 1183c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("jpeg", IMAGES); 1193c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("jpe", IMAGES); 1203c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("pcx", IMAGES); 1213c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("png", IMAGES); 1223c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("svg", IMAGES); 1233c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("svgz", IMAGES); 1243c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("tiff", IMAGES); 1253c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("tif", IMAGES); 1263c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("wbmp", IMAGES); 1273c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("webp", IMAGES); 1283c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("dng", IMAGES); 1293c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("cr2", IMAGES); 1303c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("ras", IMAGES); 1313c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("art", IMAGES); 1323c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("jng", IMAGES); 1333c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("nef", IMAGES); 1343c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("nrw", IMAGES); 1353c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("orf", IMAGES); 1363c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("rw2", IMAGES); 1373c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("pef", IMAGES); 1383c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("psd", IMAGES); 1393c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("pnm", IMAGES); 1403c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("pbm", IMAGES); 1413c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("pgm", IMAGES); 1423c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("ppm", IMAGES); 1433c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("srw", IMAGES); 1443c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("arw", IMAGES); 1453c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("rgb", IMAGES); 1463c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("xbm", IMAGES); 1473c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("xpm", IMAGES); 1483c7febdbd86070337810d1ff741d35430707726aDaniel Nishi EXTENSION_MAP.put("xwd", IMAGES); 1493c7febdbd86070337810d1ff741d35430707726aDaniel Nishi } 1503c7febdbd86070337810d1ff741d35430707726aDaniel Nishi 1513c7febdbd86070337810d1ff741d35430707726aDaniel Nishi /** 1523c7febdbd86070337810d1ff741d35430707726aDaniel Nishi * Returns the file categorization measurement result. 1533c7febdbd86070337810d1ff741d35430707726aDaniel Nishi * @param path Directory to collect and categorize storage in. 1543c7febdbd86070337810d1ff741d35430707726aDaniel Nishi */ 1553c7febdbd86070337810d1ff741d35430707726aDaniel Nishi public static MeasurementResult getMeasurementResult(File path) { 1563c7febdbd86070337810d1ff741d35430707726aDaniel Nishi return collectFiles(StorageManager.maybeTranslateEmulatedPathToInternal(path), 1573c7febdbd86070337810d1ff741d35430707726aDaniel Nishi new MeasurementResult()); 1583c7febdbd86070337810d1ff741d35430707726aDaniel Nishi } 1593c7febdbd86070337810d1ff741d35430707726aDaniel Nishi 16077a78c6f4412dccc58075685ad77f3e41d85f2e4Daniel Nishi /** 1615d230dc202cb03185652e12b3024ceea1132dd4dDaniel Nishi * Returns the file categorization result for the primary internal storage UUID. 1625d230dc202cb03185652e12b3024ceea1132dd4dDaniel Nishi * 1635d230dc202cb03185652e12b3024ceea1132dd4dDaniel Nishi * @param context 1645d230dc202cb03185652e12b3024ceea1132dd4dDaniel Nishi */ 1655d230dc202cb03185652e12b3024ceea1132dd4dDaniel Nishi public static MeasurementResult getMeasurementResult(Context context) { 1665d230dc202cb03185652e12b3024ceea1132dd4dDaniel Nishi MeasurementResult result = new MeasurementResult(); 1675d230dc202cb03185652e12b3024ceea1132dd4dDaniel Nishi StorageStatsManager ssm = 1685d230dc202cb03185652e12b3024ceea1132dd4dDaniel Nishi (StorageStatsManager) context.getSystemService(Context.STORAGE_STATS_SERVICE); 1695d230dc202cb03185652e12b3024ceea1132dd4dDaniel Nishi ExternalStorageStats stats = null; 1705d230dc202cb03185652e12b3024ceea1132dd4dDaniel Nishi try { 1715d230dc202cb03185652e12b3024ceea1132dd4dDaniel Nishi stats = 1725d230dc202cb03185652e12b3024ceea1132dd4dDaniel Nishi ssm.queryExternalStatsForUser( 1735d230dc202cb03185652e12b3024ceea1132dd4dDaniel Nishi StorageManager.UUID_PRIVATE_INTERNAL, 1745d230dc202cb03185652e12b3024ceea1132dd4dDaniel Nishi UserHandle.of(context.getUserId())); 1755d230dc202cb03185652e12b3024ceea1132dd4dDaniel Nishi result.imagesSize = stats.getImageBytes(); 1765d230dc202cb03185652e12b3024ceea1132dd4dDaniel Nishi result.videosSize = stats.getVideoBytes(); 1775d230dc202cb03185652e12b3024ceea1132dd4dDaniel Nishi result.audioSize = stats.getAudioBytes(); 1785d230dc202cb03185652e12b3024ceea1132dd4dDaniel Nishi result.miscSize = 1795d230dc202cb03185652e12b3024ceea1132dd4dDaniel Nishi stats.getTotalBytes() 1805d230dc202cb03185652e12b3024ceea1132dd4dDaniel Nishi - result.imagesSize 1815d230dc202cb03185652e12b3024ceea1132dd4dDaniel Nishi - result.videosSize 1825d230dc202cb03185652e12b3024ceea1132dd4dDaniel Nishi - result.audioSize; 1835d230dc202cb03185652e12b3024ceea1132dd4dDaniel Nishi } catch (IOException e) { 1845d230dc202cb03185652e12b3024ceea1132dd4dDaniel Nishi throw new IllegalStateException("Could not query storage"); 1855d230dc202cb03185652e12b3024ceea1132dd4dDaniel Nishi } 1865d230dc202cb03185652e12b3024ceea1132dd4dDaniel Nishi 1875d230dc202cb03185652e12b3024ceea1132dd4dDaniel Nishi return result; 1885d230dc202cb03185652e12b3024ceea1132dd4dDaniel Nishi } 1895d230dc202cb03185652e12b3024ceea1132dd4dDaniel Nishi 1905d230dc202cb03185652e12b3024ceea1132dd4dDaniel Nishi /** 19177a78c6f4412dccc58075685ad77f3e41d85f2e4Daniel Nishi * Returns the size of a system for a given context. This is done by finding the difference 19277a78c6f4412dccc58075685ad77f3e41d85f2e4Daniel Nishi * between the shared data and the total primary storage size. 1935d230dc202cb03185652e12b3024ceea1132dd4dDaniel Nishi * 19477a78c6f4412dccc58075685ad77f3e41d85f2e4Daniel Nishi * @param context Context to use to get storage information. 19577a78c6f4412dccc58075685ad77f3e41d85f2e4Daniel Nishi */ 19677a78c6f4412dccc58075685ad77f3e41d85f2e4Daniel Nishi public static long getSystemSize(Context context) { 19777a78c6f4412dccc58075685ad77f3e41d85f2e4Daniel Nishi PackageManager pm = context.getPackageManager(); 19877a78c6f4412dccc58075685ad77f3e41d85f2e4Daniel Nishi VolumeInfo primaryVolume = pm.getPrimaryStorageCurrentVolume(); 19977a78c6f4412dccc58075685ad77f3e41d85f2e4Daniel Nishi 2005d230dc202cb03185652e12b3024ceea1132dd4dDaniel Nishi StorageManager sm = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE); 20177a78c6f4412dccc58075685ad77f3e41d85f2e4Daniel Nishi VolumeInfo shared = sm.findEmulatedForPrivate(primaryVolume); 20277a78c6f4412dccc58075685ad77f3e41d85f2e4Daniel Nishi if (shared == null) { 20377a78c6f4412dccc58075685ad77f3e41d85f2e4Daniel Nishi return 0; 20477a78c6f4412dccc58075685ad77f3e41d85f2e4Daniel Nishi } 20577a78c6f4412dccc58075685ad77f3e41d85f2e4Daniel Nishi 206e4bea2d769ae9ab3df028886d61e1215e43fab6fDaniel Nishi // In some cases, the path may be null -- we can't determine the size in this case. 207e4bea2d769ae9ab3df028886d61e1215e43fab6fDaniel Nishi final File sharedPath = shared.getPath(); 208e4bea2d769ae9ab3df028886d61e1215e43fab6fDaniel Nishi if (sharedPath == null) { 209e4bea2d769ae9ab3df028886d61e1215e43fab6fDaniel Nishi return 0; 210e4bea2d769ae9ab3df028886d61e1215e43fab6fDaniel Nishi } 211e4bea2d769ae9ab3df028886d61e1215e43fab6fDaniel Nishi 212e4bea2d769ae9ab3df028886d61e1215e43fab6fDaniel Nishi final long sharedDataSize = sharedPath.getTotalSpace(); 21377a78c6f4412dccc58075685ad77f3e41d85f2e4Daniel Nishi long systemSize = sm.getPrimaryStorageSize() - sharedDataSize; 21477a78c6f4412dccc58075685ad77f3e41d85f2e4Daniel Nishi 21577a78c6f4412dccc58075685ad77f3e41d85f2e4Daniel Nishi // This case is not exceptional -- we just fallback to the shared data volume in this case. 21677a78c6f4412dccc58075685ad77f3e41d85f2e4Daniel Nishi if (systemSize <= 0) { 21777a78c6f4412dccc58075685ad77f3e41d85f2e4Daniel Nishi return 0; 21877a78c6f4412dccc58075685ad77f3e41d85f2e4Daniel Nishi } 21977a78c6f4412dccc58075685ad77f3e41d85f2e4Daniel Nishi 22077a78c6f4412dccc58075685ad77f3e41d85f2e4Daniel Nishi return systemSize; 22177a78c6f4412dccc58075685ad77f3e41d85f2e4Daniel Nishi } 22277a78c6f4412dccc58075685ad77f3e41d85f2e4Daniel Nishi 2233c7febdbd86070337810d1ff741d35430707726aDaniel Nishi private static MeasurementResult collectFiles(File file, MeasurementResult result) { 2243c7febdbd86070337810d1ff741d35430707726aDaniel Nishi File[] files = file.listFiles(); 2253c7febdbd86070337810d1ff741d35430707726aDaniel Nishi 2263c7febdbd86070337810d1ff741d35430707726aDaniel Nishi if (files == null) { 2273c7febdbd86070337810d1ff741d35430707726aDaniel Nishi return result; 2283c7febdbd86070337810d1ff741d35430707726aDaniel Nishi } 2293c7febdbd86070337810d1ff741d35430707726aDaniel Nishi 2303c7febdbd86070337810d1ff741d35430707726aDaniel Nishi for (File f : files) { 2313c7febdbd86070337810d1ff741d35430707726aDaniel Nishi if (f.isDirectory()) { 2323c7febdbd86070337810d1ff741d35430707726aDaniel Nishi try { 2333c7febdbd86070337810d1ff741d35430707726aDaniel Nishi collectFiles(f, result); 2343c7febdbd86070337810d1ff741d35430707726aDaniel Nishi } catch (StackOverflowError e) { 2353c7febdbd86070337810d1ff741d35430707726aDaniel Nishi return result; 2363c7febdbd86070337810d1ff741d35430707726aDaniel Nishi } 2373c7febdbd86070337810d1ff741d35430707726aDaniel Nishi } else { 2383c7febdbd86070337810d1ff741d35430707726aDaniel Nishi handleFile(result, f); 2393c7febdbd86070337810d1ff741d35430707726aDaniel Nishi } 2403c7febdbd86070337810d1ff741d35430707726aDaniel Nishi } 2413c7febdbd86070337810d1ff741d35430707726aDaniel Nishi 2423c7febdbd86070337810d1ff741d35430707726aDaniel Nishi return result; 2433c7febdbd86070337810d1ff741d35430707726aDaniel Nishi } 2443c7febdbd86070337810d1ff741d35430707726aDaniel Nishi 2453c7febdbd86070337810d1ff741d35430707726aDaniel Nishi private static void handleFile(MeasurementResult result, File f) { 2463c7febdbd86070337810d1ff741d35430707726aDaniel Nishi long fileSize = f.length(); 2473c7febdbd86070337810d1ff741d35430707726aDaniel Nishi int fileType = EXTENSION_MAP.getOrDefault(getExtensionForFile(f), UNRECOGNIZED); 2483c7febdbd86070337810d1ff741d35430707726aDaniel Nishi switch (fileType) { 2493c7febdbd86070337810d1ff741d35430707726aDaniel Nishi case AUDIO: 2503c7febdbd86070337810d1ff741d35430707726aDaniel Nishi result.audioSize += fileSize; 2513c7febdbd86070337810d1ff741d35430707726aDaniel Nishi break; 2523c7febdbd86070337810d1ff741d35430707726aDaniel Nishi case VIDEO: 2533c7febdbd86070337810d1ff741d35430707726aDaniel Nishi result.videosSize += fileSize; 2543c7febdbd86070337810d1ff741d35430707726aDaniel Nishi break; 2553c7febdbd86070337810d1ff741d35430707726aDaniel Nishi case IMAGES: 2563c7febdbd86070337810d1ff741d35430707726aDaniel Nishi result.imagesSize += fileSize; 2573c7febdbd86070337810d1ff741d35430707726aDaniel Nishi break; 2583c7febdbd86070337810d1ff741d35430707726aDaniel Nishi default: 2593c7febdbd86070337810d1ff741d35430707726aDaniel Nishi result.miscSize += fileSize; 2603c7febdbd86070337810d1ff741d35430707726aDaniel Nishi } 2613c7febdbd86070337810d1ff741d35430707726aDaniel Nishi } 2623c7febdbd86070337810d1ff741d35430707726aDaniel Nishi 2633c7febdbd86070337810d1ff741d35430707726aDaniel Nishi private static String getExtensionForFile(File file) { 2643c7febdbd86070337810d1ff741d35430707726aDaniel Nishi String fileName = file.getName(); 2653c7febdbd86070337810d1ff741d35430707726aDaniel Nishi int index = fileName.lastIndexOf('.'); 2663c7febdbd86070337810d1ff741d35430707726aDaniel Nishi if (index == -1) { 2673c7febdbd86070337810d1ff741d35430707726aDaniel Nishi return ""; 2683c7febdbd86070337810d1ff741d35430707726aDaniel Nishi } 2693c7febdbd86070337810d1ff741d35430707726aDaniel Nishi return fileName.substring(index + 1).toLowerCase(); 2703c7febdbd86070337810d1ff741d35430707726aDaniel Nishi } 2713c7febdbd86070337810d1ff741d35430707726aDaniel Nishi 2723c7febdbd86070337810d1ff741d35430707726aDaniel Nishi /** 2733c7febdbd86070337810d1ff741d35430707726aDaniel Nishi * MeasurementResult contains a storage categorization result. 2743c7febdbd86070337810d1ff741d35430707726aDaniel Nishi */ 2753c7febdbd86070337810d1ff741d35430707726aDaniel Nishi public static class MeasurementResult { 2763c7febdbd86070337810d1ff741d35430707726aDaniel Nishi public long imagesSize; 2773c7febdbd86070337810d1ff741d35430707726aDaniel Nishi public long videosSize; 2783c7febdbd86070337810d1ff741d35430707726aDaniel Nishi public long miscSize; 2793c7febdbd86070337810d1ff741d35430707726aDaniel Nishi public long audioSize; 2803c7febdbd86070337810d1ff741d35430707726aDaniel Nishi 2813c7febdbd86070337810d1ff741d35430707726aDaniel Nishi /** 2823c7febdbd86070337810d1ff741d35430707726aDaniel Nishi * Sums up the storage taken by all of the categorizable sizes in the measurement. 2833c7febdbd86070337810d1ff741d35430707726aDaniel Nishi */ 2843c7febdbd86070337810d1ff741d35430707726aDaniel Nishi public long totalAccountedSize() { 2853c7febdbd86070337810d1ff741d35430707726aDaniel Nishi return imagesSize + videosSize + miscSize + audioSize; 2863c7febdbd86070337810d1ff741d35430707726aDaniel Nishi } 2873c7febdbd86070337810d1ff741d35430707726aDaniel Nishi } 2883c7febdbd86070337810d1ff741d35430707726aDaniel Nishi} 289