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"/>
<Preference
android:key="contour_lines_and_hillshade_memory"
android:key="terrain_memory_used"
android:layout="@layout/data_storage_memory_used_item"
android:icon="@drawable/ic_map"
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 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 NOTES_MEMORY = "notes_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 MemoryItem mapsMemory;
private MemoryItem srtmAndHillshadeMemory;
private MemoryItem terrainMemory;
private MemoryItem tracksMemory;
private MemoryItem notesMemory;
private MemoryItem tilesMemory;
@ -186,15 +186,15 @@ public class DataStorageHelper {
.createItem();
memoryItems.add(mapsMemory);
srtmAndHillshadeMemory = MemoryItem.builder()
.setKey(SRTM_AND_HILLSHADE_MEMORY)
terrainMemory = MemoryItem.builder()
.setKey(TERRAIN_MEMORY)
.setExtensions(IndexConstants.BINARY_SRTM_MAP_INDEX_EXT)
.setDirectories(
createDirectory((SRTM_INDEX_DIR), true, EXTENSIONS, false),
createDirectory((TILES_INDEX_DIR), false, PREFIX, true))
.setPrefixes("Hillshade")
.createItem();
memoryItems.add(srtmAndHillshadeMemory);
memoryItems.add(terrainMemory);
tracksMemory = MemoryItem.builder()
.setKey(TRACKS_MEMORY)
@ -267,13 +267,13 @@ public class DataStorageHelper {
public RefreshUsedMemoryTask calculateMemoryUsedInfo(UpdateMemoryInfoUIAdapter listener) {
File rootDir = new File(currentStoragePath);
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;
}
public RefreshUsedMemoryTask calculateTilesMemoryUsed(UpdateMemoryInfoUIAdapter listener) {
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);
return task;
}
@ -290,11 +290,11 @@ public class DataStorageHelper {
}
public DirectoryItem createDirectory(@NonNull String relativePath,
boolean goDeeper,
boolean processInternalDirectories,
CheckingType checkingType,
boolean skipOther) {
boolean skipUnmatchedInDirectory) {
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) {

View file

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

View file

@ -2,6 +2,8 @@ package net.osmand.plus.settings.datastorage.task;
import android.os.AsyncTask;
import androidx.annotation.NonNull;
import net.osmand.plus.settings.datastorage.DataStorageHelper.UpdateMemoryInfoUIAdapter;
import net.osmand.plus.settings.datastorage.item.DirectoryItem;
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 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> {
private UpdateMemoryInfoUIAdapter listener;
private File rootDir;
private MemoryItem otherMemory;
private String[] directoriesToAvoid;
private String[] prefixesToAvoid;
private String taskKey;
private final UpdateMemoryInfoUIAdapter uiAdapter;
private final File root;
private final MemoryItem otherMemoryItem;
private final String[] directoriesToSkip;
private final String[] filePrefixesToSkip;
private final String tag;
private long lastRefreshTime;
public RefreshUsedMemoryTask(UpdateMemoryInfoUIAdapter listener, MemoryItem otherMemory, File rootDir, String[] directoriesToAvoid, String[] prefixesToAvoid, String taskKey) {
this.listener = listener;
this.otherMemory = otherMemory;
this.rootDir = rootDir;
this.directoriesToAvoid = directoriesToAvoid;
this.prefixesToAvoid = prefixesToAvoid;
this.taskKey = taskKey;
public RefreshUsedMemoryTask(UpdateMemoryInfoUIAdapter uiAdapter,
MemoryItem otherMemoryItem,
File root,
String[] directoriesToSkip,
String[] filePrefixesToSkip,
String tag) {
this.uiAdapter = uiAdapter;
this.otherMemoryItem = otherMemoryItem;
this.root = root;
this.directoriesToSkip = directoriesToSkip;
this.filePrefixesToSkip = filePrefixesToSkip;
this.tag = tag;
}
@Override
protected Void doInBackground(MemoryItem... items) {
lastRefreshTime = System.currentTimeMillis();
if (rootDir.canRead()) {
calculateMultiTypes(rootDir, items);
if (root.canRead()) {
calculateMultiTypes(root, items);
}
return null;
}
private void calculateMultiTypes(File rootDir, MemoryItem... items) {
private void calculateMultiTypes(File rootDir,
MemoryItem... items) {
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()) {
//check current directory should be avoid
if (directoriesToAvoid != null) {
for (String directoryToAvoid : directoriesToAvoid) {
if (file.getAbsolutePath().equals(directoryToAvoid)) {
break nextFile;
}
}
if (!shouldSkipDirectory(file)) {
processDirectory(file, items);
}
//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()) {
//check current file should be avoid
if (prefixesToAvoid != null) {
for (String prefixToAvoid : prefixesToAvoid) {
if (file.getName().toLowerCase().startsWith(prefixToAvoid.toLowerCase())) {
break nextFile;
}
}
if (!shouldSkipFile(file)) {
processFile(rootDir, file, items);
}
//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;
if (dir.isDirectory()) {
File[] files = dir.listFiles();
if (files == null) return 0;
for (File file : files) {
if (isCancelled()) {
break;
}
if (file.isDirectory()) {
bytes += getDirectorySize(file);
bytes += calculateFolderSize(file);
} else if (file.isFile()) {
bytes += file.length();
}
@ -161,16 +206,16 @@ public class RefreshUsedMemoryTask extends AsyncTask<MemoryItem, Void, Void> {
@Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
if (listener != null) {
listener.onMemoryInfoUpdate();
if (uiAdapter != null) {
uiAdapter.onMemoryInfoUpdate();
}
}
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
if (listener != null) {
listener.onFinishUpdating(taskKey);
if (uiAdapter != null) {
uiAdapter.onFinishUpdating(tag);
}
}