Data storage refactoring, step 2

This commit is contained in:
nazar-kutz 2021-02-01 20:30:59 +02:00
parent 353c2d1676
commit 7041c4ecc9
4 changed files with 178 additions and 133 deletions

View file

@ -14,7 +14,7 @@
android:title="@string/shared_string_maps"/> android:title="@string/shared_string_maps"/>
<Preference <Preference
android:key="contour_lines_and_hillshade_memory" android:key="terrain_memory_used"
android:layout="@layout/data_storage_memory_used_item" android:layout="@layout/data_storage_memory_used_item"
android:icon="@drawable/ic_map" android:icon="@drawable/ic_map"
android:title="@string/contour_lines_and_hillshade"/> android:title="@string/contour_lines_and_hillshade"/>

View file

@ -39,7 +39,7 @@ public class DataStorageHelper {
public final static String MANUALLY_SPECIFIED = "manually_specified"; public final static String MANUALLY_SPECIFIED = "manually_specified";
public final static String MAPS_MEMORY = "maps_memory_used"; public final static String MAPS_MEMORY = "maps_memory_used";
public final static String SRTM_AND_HILLSHADE_MEMORY = "contour_lines_and_hillshade_memory"; public final static String TERRAIN_MEMORY = "terrain_memory_used";
public final static String TRACKS_MEMORY = "tracks_memory_used"; public final static String TRACKS_MEMORY = "tracks_memory_used";
public final static String NOTES_MEMORY = "notes_memory_used"; public final static String NOTES_MEMORY = "notes_memory_used";
public final static String TILES_MEMORY = "tiles_memory_used"; public final static String TILES_MEMORY = "tiles_memory_used";
@ -52,7 +52,7 @@ public class DataStorageHelper {
private ArrayList<MemoryItem> memoryItems = new ArrayList<>(); private ArrayList<MemoryItem> memoryItems = new ArrayList<>();
private MemoryItem mapsMemory; private MemoryItem mapsMemory;
private MemoryItem srtmAndHillshadeMemory; private MemoryItem terrainMemory;
private MemoryItem tracksMemory; private MemoryItem tracksMemory;
private MemoryItem notesMemory; private MemoryItem notesMemory;
private MemoryItem tilesMemory; private MemoryItem tilesMemory;
@ -186,15 +186,15 @@ public class DataStorageHelper {
.createItem(); .createItem();
memoryItems.add(mapsMemory); memoryItems.add(mapsMemory);
srtmAndHillshadeMemory = MemoryItem.builder() terrainMemory = MemoryItem.builder()
.setKey(SRTM_AND_HILLSHADE_MEMORY) .setKey(TERRAIN_MEMORY)
.setExtensions(IndexConstants.BINARY_SRTM_MAP_INDEX_EXT) .setExtensions(IndexConstants.BINARY_SRTM_MAP_INDEX_EXT)
.setDirectories( .setDirectories(
createDirectory((SRTM_INDEX_DIR), true, EXTENSIONS, false), createDirectory((SRTM_INDEX_DIR), true, EXTENSIONS, false),
createDirectory((TILES_INDEX_DIR), false, PREFIX, true)) createDirectory((TILES_INDEX_DIR), false, PREFIX, true))
.setPrefixes("Hillshade") .setPrefixes("Hillshade")
.createItem(); .createItem();
memoryItems.add(srtmAndHillshadeMemory); memoryItems.add(terrainMemory);
tracksMemory = MemoryItem.builder() tracksMemory = MemoryItem.builder()
.setKey(TRACKS_MEMORY) .setKey(TRACKS_MEMORY)
@ -267,13 +267,13 @@ public class DataStorageHelper {
public RefreshUsedMemoryTask calculateMemoryUsedInfo(UpdateMemoryInfoUIAdapter listener) { public RefreshUsedMemoryTask calculateMemoryUsedInfo(UpdateMemoryInfoUIAdapter listener) {
File rootDir = new File(currentStoragePath); File rootDir = new File(currentStoragePath);
RefreshUsedMemoryTask task = new RefreshUsedMemoryTask(listener, otherMemory, rootDir, null, null, OTHER_MEMORY); RefreshUsedMemoryTask task = new RefreshUsedMemoryTask(listener, otherMemory, rootDir, null, null, OTHER_MEMORY);
task.execute(mapsMemory, srtmAndHillshadeMemory, tracksMemory, notesMemory); task.execute(mapsMemory, terrainMemory, tracksMemory, notesMemory);
return task; return task;
} }
public RefreshUsedMemoryTask calculateTilesMemoryUsed(UpdateMemoryInfoUIAdapter listener) { public RefreshUsedMemoryTask calculateTilesMemoryUsed(UpdateMemoryInfoUIAdapter listener) {
File rootDir = new File(tilesMemory.getDirectories()[0].getAbsolutePath()); File rootDir = new File(tilesMemory.getDirectories()[0].getAbsolutePath());
RefreshUsedMemoryTask task = new RefreshUsedMemoryTask(listener, otherMemory, rootDir, null, srtmAndHillshadeMemory.getPrefixes(), TILES_MEMORY); RefreshUsedMemoryTask task = new RefreshUsedMemoryTask(listener, otherMemory, rootDir, null, terrainMemory.getPrefixes(), TILES_MEMORY);
task.execute(tilesMemory); task.execute(tilesMemory);
return task; return task;
} }
@ -290,11 +290,11 @@ public class DataStorageHelper {
} }
public DirectoryItem createDirectory(@NonNull String relativePath, public DirectoryItem createDirectory(@NonNull String relativePath,
boolean goDeeper, boolean processInternalDirectories,
CheckingType checkingType, CheckingType checkingType,
boolean skipOther) { boolean skipUnmatchedInDirectory) {
String path = app.getAppPath(relativePath).getAbsolutePath(); String path = app.getAppPath(relativePath).getAbsolutePath();
return new DirectoryItem(path, goDeeper, checkingType, skipOther); return new DirectoryItem(path, processInternalDirectories, checkingType, skipUnmatchedInDirectory);
} }
public static String getFormattedMemoryInfo(long bytes, String[] formatStrings) { public static String getFormattedMemoryInfo(long bytes, String[] formatStrings) {

View file

@ -3,9 +3,9 @@ package net.osmand.plus.settings.datastorage.item;
public class DirectoryItem { public class DirectoryItem {
private final String absolutePath; private final String absolutePath;
private final boolean goDeeper; private final boolean processInternalDirectories;
private final CheckingType checkingType; private final CheckingType checkingType;
private final boolean skipOther; private final boolean skipUnmatchedInDirectory;
public enum CheckingType { public enum CheckingType {
EXTENSIONS, EXTENSIONS,
@ -13,28 +13,28 @@ public class DirectoryItem {
} }
public DirectoryItem(String absolutePath, public DirectoryItem(String absolutePath,
boolean goDeeper, boolean processInternalDirectories,
CheckingType checkingType, CheckingType checkingType,
boolean skipOther) { boolean skipUnmatchedInDirectory) {
this.absolutePath = absolutePath; this.absolutePath = absolutePath;
this.goDeeper = goDeeper; this.processInternalDirectories = processInternalDirectories;
this.checkingType = checkingType; this.checkingType = checkingType;
this.skipOther = skipOther; this.skipUnmatchedInDirectory = skipUnmatchedInDirectory;
} }
public String getAbsolutePath() { public String getAbsolutePath() {
return absolutePath; return absolutePath;
} }
public boolean isGoDeeper() { public boolean shouldProcessInternalDirectories() {
return goDeeper; return processInternalDirectories;
} }
public CheckingType getCheckingType() { public CheckingType getCheckingType() {
return checkingType; return checkingType;
} }
public boolean isSkipOther() { public boolean shouldSkipUnmatchedInDirectory() {
return skipOther; return skipUnmatchedInDirectory;
} }
} }

View file

@ -2,6 +2,8 @@ package net.osmand.plus.settings.datastorage.task;
import android.os.AsyncTask; import android.os.AsyncTask;
import androidx.annotation.NonNull;
import net.osmand.plus.settings.datastorage.DataStorageHelper.UpdateMemoryInfoUIAdapter; import net.osmand.plus.settings.datastorage.DataStorageHelper.UpdateMemoryInfoUIAdapter;
import net.osmand.plus.settings.datastorage.item.DirectoryItem; import net.osmand.plus.settings.datastorage.item.DirectoryItem;
import net.osmand.plus.settings.datastorage.item.DirectoryItem.CheckingType; import net.osmand.plus.settings.datastorage.item.DirectoryItem.CheckingType;
@ -10,146 +12,189 @@ import net.osmand.plus.settings.datastorage.item.MemoryItem;
import java.io.File; import java.io.File;
import static net.osmand.plus.settings.datastorage.DataStorageFragment.UI_REFRESH_TIME_MS; import static net.osmand.plus.settings.datastorage.DataStorageFragment.UI_REFRESH_TIME_MS;
import static net.osmand.util.Algorithms.objectEquals;
public class RefreshUsedMemoryTask extends AsyncTask<MemoryItem, Void, Void> { public class RefreshUsedMemoryTask extends AsyncTask<MemoryItem, Void, Void> {
private UpdateMemoryInfoUIAdapter listener; private final UpdateMemoryInfoUIAdapter uiAdapter;
private File rootDir; private final File root;
private MemoryItem otherMemory; private final MemoryItem otherMemoryItem;
private String[] directoriesToAvoid; private final String[] directoriesToSkip;
private String[] prefixesToAvoid; private final String[] filePrefixesToSkip;
private String taskKey; private final String tag;
private long lastRefreshTime; private long lastRefreshTime;
public RefreshUsedMemoryTask(UpdateMemoryInfoUIAdapter listener, MemoryItem otherMemory, File rootDir, String[] directoriesToAvoid, String[] prefixesToAvoid, String taskKey) { public RefreshUsedMemoryTask(UpdateMemoryInfoUIAdapter uiAdapter,
this.listener = listener; MemoryItem otherMemoryItem,
this.otherMemory = otherMemory; File root,
this.rootDir = rootDir; String[] directoriesToSkip,
this.directoriesToAvoid = directoriesToAvoid; String[] filePrefixesToSkip,
this.prefixesToAvoid = prefixesToAvoid; String tag) {
this.taskKey = taskKey; this.uiAdapter = uiAdapter;
this.otherMemoryItem = otherMemoryItem;
this.root = root;
this.directoriesToSkip = directoriesToSkip;
this.filePrefixesToSkip = filePrefixesToSkip;
this.tag = tag;
} }
@Override @Override
protected Void doInBackground(MemoryItem... items) { protected Void doInBackground(MemoryItem... items) {
lastRefreshTime = System.currentTimeMillis(); lastRefreshTime = System.currentTimeMillis();
if (rootDir.canRead()) { if (root.canRead()) {
calculateMultiTypes(rootDir, items); calculateMultiTypes(root, items);
} }
return null; return null;
} }
private void calculateMultiTypes(File rootDir, MemoryItem... items) { private void calculateMultiTypes(File rootDir,
MemoryItem... items) {
File[] subFiles = rootDir.listFiles(); File[] subFiles = rootDir.listFiles();
if (subFiles != null) {
for (File file : subFiles) {
if (isCancelled()) break;
for (File file : subFiles) {
if (isCancelled()) {
break;
}
nextFile : {
if (file.isDirectory()) { if (file.isDirectory()) {
//check current directory should be avoid if (!shouldSkipDirectory(file)) {
if (directoriesToAvoid != null) { processDirectory(file, items);
for (String directoryToAvoid : directoriesToAvoid) {
if (file.getAbsolutePath().equals(directoryToAvoid)) {
break nextFile;
}
}
} }
//check current directory matched items type
for (MemoryItem item : items) {
DirectoryItem[] directories = item.getDirectories();
if (directories == null) {
continue;
}
for (DirectoryItem dir : directories) {
if (file.getAbsolutePath().equals(dir.getAbsolutePath())
|| (file.getAbsolutePath().startsWith(dir.getAbsolutePath()))) {
if (dir.isGoDeeper()) {
calculateMultiTypes(file, items);
break nextFile;
} else if (dir.isSkipOther()) {
break nextFile;
}
}
}
}
//current directory did not match to any type
otherMemory.addBytes(getDirectorySize(file));
} else if (file.isFile()) { } else if (file.isFile()) {
//check current file should be avoid if (!shouldSkipFile(file)) {
if (prefixesToAvoid != null) { processFile(rootDir, file, items);
for (String prefixToAvoid : prefixesToAvoid) {
if (file.getName().toLowerCase().startsWith(prefixToAvoid.toLowerCase())) {
break nextFile;
}
}
} }
//check current file matched items type
for (MemoryItem item : items) {
DirectoryItem[] directories = item.getDirectories();
if (directories == null) {
continue;
}
for (DirectoryItem dir : directories) {
if (rootDir.getAbsolutePath().equals(dir.getAbsolutePath())
|| (rootDir.getAbsolutePath().startsWith(dir.getAbsolutePath()) && dir.isGoDeeper())) {
CheckingType checkingType = dir.getCheckingType();
switch (checkingType) {
case EXTENSIONS : {
String[] extensions = item.getExtensions();
if (extensions != null) {
for (String extension : extensions) {
if (file.getAbsolutePath().endsWith(extension)) {
item.addBytes(file.length());
break nextFile;
}
}
} else {
item.addBytes(file.length());
break nextFile;
}
break ;
}
case PREFIX : {
String[] prefixes = item.getPrefixes();
if (prefixes != null) {
for (String prefix : prefixes) {
if (file.getName().toLowerCase().startsWith(prefix.toLowerCase())) {
item.addBytes(file.length());
break nextFile;
}
}
} else {
item.addBytes(file.length());
break nextFile;
}
break ;
}
}
if (dir.isSkipOther()) {
break nextFile;
}
}
}
}
//current file did not match any type
otherMemory.addBytes(file.length());
} }
refreshUI();
} }
refreshUI();
} }
} }
private long getDirectorySize(File dir) { private boolean shouldSkipDirectory(@NonNull File dir) {
if (directoriesToSkip != null) {
for (String dirToSkipPath : directoriesToSkip) {
String dirPath = dir.getAbsolutePath();
if (objectEquals(dirPath, dirToSkipPath)) {
return true;
}
}
}
return false;
}
private boolean shouldSkipFile(@NonNull File file) {
if (filePrefixesToSkip != null) {
String fileName = file.getName().toLowerCase();
for (String prefixToAvoid : filePrefixesToSkip) {
String prefix = prefixToAvoid.toLowerCase();
if (fileName.startsWith(prefix)) {
return true;
}
}
}
return false;
}
private void processDirectory(@NonNull File directory,
@NonNull MemoryItem... items) {
String directoryPath = directory.getAbsolutePath();
for (MemoryItem memoryItem : items) {
DirectoryItem[] allowedDirectories = memoryItem.getDirectories();
if (allowedDirectories != null) {
for (DirectoryItem allowedDir : allowedDirectories) {
String allowedDirPath = allowedDir.getAbsolutePath();
if (objectEquals(directoryPath, allowedDirPath)
|| (directoryPath.startsWith(allowedDirPath))) {
if (allowedDir.shouldProcessInternalDirectories()) {
calculateMultiTypes(directory, items);
return;
} else if (allowedDir.shouldSkipUnmatchedInDirectory()) {
return;
}
}
}
}
}
// Current directory did not match to any type
otherMemoryItem.addBytes(calculateFolderSize(directory));
}
private void processFile(@NonNull File rootDir,
@NonNull File file,
@NonNull MemoryItem... items) {
for (MemoryItem item : items) {
DirectoryItem[] allowedDirectories = item.getDirectories();
if (allowedDirectories == null) continue;
String rootDirPath = rootDir.getAbsolutePath();
for (DirectoryItem allowedDir : allowedDirectories) {
String allowedDirPath = allowedDir.getAbsolutePath();
boolean processInternal = allowedDir.shouldProcessInternalDirectories();
if (objectEquals(rootDirPath, allowedDirPath)
|| (rootDirPath.startsWith(allowedDirPath) && processInternal)) {
CheckingType checkingType = allowedDir.getCheckingType();
switch (checkingType) {
case EXTENSIONS: {
if (isSuitableExtension(file, item)) {
item.addBytes(file.length());
return;
}
break;
}
case PREFIX: {
if (isSuitablePrefix(file, item)) {
item.addBytes(file.length());
return;
}
break;
}
}
if (allowedDir.shouldSkipUnmatchedInDirectory()) {
return;
}
}
}
}
// Current file did not match any type
otherMemoryItem.addBytes(file.length());
}
private boolean isSuitableExtension(@NonNull File file,
@NonNull MemoryItem item) {
String[] extensions = item.getExtensions();
if (extensions != null) {
for (String extension : extensions) {
if (file.getAbsolutePath().endsWith(extension)) {
return true;
}
}
}
return extensions == null;
}
private boolean isSuitablePrefix(@NonNull File file,
@NonNull MemoryItem item) {
String[] prefixes = item.getPrefixes();
if (prefixes != null) {
for (String prefix : prefixes) {
if (file.getName().toLowerCase().startsWith(prefix.toLowerCase())) {
return true;
}
}
}
return prefixes == null;
}
private long calculateFolderSize(@NonNull File dir) {
long bytes = 0; long bytes = 0;
if (dir.isDirectory()) { if (dir.isDirectory()) {
File[] files = dir.listFiles(); File[] files = dir.listFiles();
if (files == null) return 0;
for (File file : files) { for (File file : files) {
if (isCancelled()) { if (isCancelled()) {
break; break;
} }
if (file.isDirectory()) { if (file.isDirectory()) {
bytes += getDirectorySize(file); bytes += calculateFolderSize(file);
} else if (file.isFile()) { } else if (file.isFile()) {
bytes += file.length(); bytes += file.length();
} }
@ -161,16 +206,16 @@ public class RefreshUsedMemoryTask extends AsyncTask<MemoryItem, Void, Void> {
@Override @Override
protected void onProgressUpdate(Void... values) { protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values); super.onProgressUpdate(values);
if (listener != null) { if (uiAdapter != null) {
listener.onMemoryInfoUpdate(); uiAdapter.onMemoryInfoUpdate();
} }
} }
@Override @Override
protected void onPostExecute(Void aVoid) { protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid); super.onPostExecute(aVoid);
if (listener != null) { if (uiAdapter != null) {
listener.onFinishUpdating(taskKey); uiAdapter.onFinishUpdating(tag);
} }
} }