Clover Coverage Report - Subsonic-Android Coverage Report
Coverage timestamp: ven dic 19 2014 17:57:13 EST
../../../../../img/srcFileCovDistChart9.png 32% of files have more coverage
73   171   24   9,12
24   129   0,33   8
8     3  
1    
This report was generated with an evaluation server license. Purchase Clover or configure your license.
 
  CacheCleaner       Line # 21 73 24 90,5% 0.9047619
 
No Tests
 
1    package net.sourceforge.subsonic.androidapp.util;
2   
3    import java.io.File;
4    import java.util.ArrayList;
5    import java.util.Collections;
6    import java.util.Comparator;
7    import java.util.HashSet;
8    import java.util.List;
9    import java.util.Set;
10   
11    import android.content.Context;
12    import android.util.Log;
13    import android.os.StatFs;
14    import net.sourceforge.subsonic.androidapp.service.DownloadFile;
15    import net.sourceforge.subsonic.androidapp.service.DownloadService;
16   
17    /**
18    * @author Sindre Mehus
19    * @version $Id$
20    */
 
21    public class CacheCleaner {
22   
23    private static final String TAG = CacheCleaner.class.getSimpleName();
24    private static final double MAX_FILE_SYSTEM_USAGE = 0.95;
25   
26    private final Context context;
27    private final DownloadService downloadService;
28   
 
29  21 toggle public CacheCleaner(Context context, DownloadService downloadService) {
30  21 this.context = context;
31  21 this.downloadService = downloadService;
32    }
33   
 
34  21 toggle public void clean() {
35   
36  21 Log.i(TAG, "Starting cache cleaning.");
37   
38  21 if (downloadService == null) {
39  0 Log.e(TAG, "DownloadService not set. Aborting cache cleaning.");
40  0 return;
41    }
42   
43  21 try {
44   
45  21 List<File> files = new ArrayList<File>();
46  21 List<File> dirs = new ArrayList<File>();
47   
48  21 findCandidatesForDeletion(FileUtil.getMusicDirectory(context), files, dirs);
49  21 sortByAscendingModificationTime(files);
50   
51  21 Set<File> undeletable = findUndeletableFiles();
52   
53  21 deleteFiles(files, undeletable);
54  21 deleteEmptyDirs(dirs, undeletable);
55  21 Log.i(TAG, "Completed cache cleaning.");
56   
57    } catch (RuntimeException x) {
58  0 Log.e(TAG, "Error in cache cleaning.", x);
59    }
60    }
61   
 
62  21 toggle private void deleteEmptyDirs(List<File> dirs, Set<File> undeletable) {
63  21 for (File dir : dirs) {
64  250 if (undeletable.contains(dir)) {
65  21 continue;
66    }
67   
68  229 File[] children = dir.listFiles();
69   
70    // Delete empty directory and associated album artwork.
71  229 if (children.length == 0) {
72  9 Util.delete(dir);
73  9 Util.delete(FileUtil.getAlbumArtFile(dir));
74    }
75    }
76    }
77   
 
78  21 toggle private void deleteFiles(List<File> files, Set<File> undeletable) {
79   
80  21 if (files.isEmpty()) {
81  0 return;
82    }
83   
84  21 long cacheSizeBytes = Util.getCacheSizeMB(context) * 1024L * 1024L;
85   
86  21 long bytesUsedBySubsonic = 0L;
87  21 for (File file : files) {
88  212 bytesUsedBySubsonic += file.length();
89    }
90   
91    // Ensure that file system is not more than 95% full.
92  21 StatFs stat = new StatFs(files.get(0).getPath());
93  21 long bytesTotalFs = (long) stat.getBlockCount() * (long) stat.getBlockSize();
94  21 long bytesAvailableFs = (long) stat.getAvailableBlocks() * (long) stat.getBlockSize();
95  21 long bytesUsedFs = bytesTotalFs - bytesAvailableFs;
96  21 long minFsAvailability = Math.round(MAX_FILE_SYSTEM_USAGE * (double) bytesTotalFs);
97   
98  21 long bytesToDeleteCacheLimit = Math.max(bytesUsedBySubsonic - cacheSizeBytes, 0L);
99  21 long bytesToDeleteFsLimit = Math.max(bytesUsedFs - minFsAvailability, 0L);
100  21 long bytesToDelete = Math.max(bytesToDeleteCacheLimit, bytesToDeleteFsLimit);
101   
102  21 Log.i(TAG, "File system : " + Util.formatBytes(bytesAvailableFs) + " of " + Util.formatBytes(bytesTotalFs) + " available");
103  21 Log.i(TAG, "Cache limit : " + Util.formatBytes(cacheSizeBytes));
104  21 Log.i(TAG, "Cache size before : " + Util.formatBytes(bytesUsedBySubsonic));
105  21 Log.i(TAG, "Minimum to delete : " + Util.formatBytes(bytesToDelete));
106   
107  21 long bytesDeleted = 0L;
108  21 for (File file : files) {
109   
110  212 if (file.getName().equals(Constants.ALBUM_ART_FILE)) {
111    // Move artwork to new folder.
112  0 file.renameTo(FileUtil.getAlbumArtFile(file.getParentFile()));
113   
114  212 } else if (bytesToDelete > bytesDeleted || file.getName().endsWith(".partial") || file.getName().contains(".partial.")) {
115  60 if (!undeletable.contains(file)) {
116  12 long size = file.length();
117  12 if (Util.delete(file)) {
118  12 bytesDeleted += size;
119    }
120    }
121    }
122    }
123   
124  21 Log.i(TAG, "Deleted : " + Util.formatBytes(bytesDeleted));
125  21 Log.i(TAG, "Cache size after : " + Util.formatBytes(bytesUsedBySubsonic - bytesDeleted));
126    }
127   
 
128  462 toggle private void findCandidatesForDeletion(File file, List<File> files, List<File> dirs) {
129  462 if (file.isFile()) {
130  212 String name = file.getName();
131  212 boolean isCacheFile = name.endsWith(".partial") || name.contains(".partial.") || name.endsWith(".complete") || name.contains(".complete.");
132  212 boolean isAlbumArtFile = name.equals(Constants.ALBUM_ART_FILE);
133  212 if (isCacheFile || isAlbumArtFile) {
134  212 files.add(file);
135    }
136    } else {
137    // Depth-first
138  250 for (File child : FileUtil.listFiles(file)) {
139  441 findCandidatesForDeletion(child, files, dirs);
140    }
141  250 dirs.add(file);
142    }
143    }
144   
 
145  21 toggle private void sortByAscendingModificationTime(List<File> files) {
146  21 Collections.sort(files, new Comparator<File>() {
 
147  494 toggle @Override
148    public int compare(File a, File b) {
149  494 if (a.lastModified() < b.lastModified()) {
150  329 return -1;
151    }
152  165 if (a.lastModified() > b.lastModified()) {
153  160 return 1;
154    }
155  5 return 0;
156    }
157    });
158    }
159   
 
160  21 toggle private Set<File> findUndeletableFiles() {
161  21 Set<File> undeletable = new HashSet<File>(5);
162   
163  21 for (DownloadFile downloadFile : downloadService.getDownloads()) {
164  251 undeletable.add(downloadFile.getPartialFile());
165  251 undeletable.add(downloadFile.getCompleteFile());
166    }
167   
168  21 undeletable.add(FileUtil.getMusicDirectory(context));
169  21 return undeletable;
170    }
171    }