Skip to content

Commit

Permalink
#169: IFile with strategyId support
Browse files Browse the repository at this point in the history
  • Loading branch information
k3b committed Mar 15, 2021
1 parent c478c46 commit 4f8a3e4
Show file tree
Hide file tree
Showing 8 changed files with 172 additions and 40 deletions.
17 changes: 13 additions & 4 deletions app/src/main/java/de/k3b/android/io/AndroidFileFacade.java
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,8 @@ public void set(IFile src) {
super.set(src);
}

public static DocumentFile getDocumentFileOrDirOrNull(@NonNull File file) {
return documentFileTranslator.getDocumentFileOrDirOrNull(file, null);
private DocumentFile getDocumentFileOrDirOrNull(@NonNull File file) {
return documentFileTranslator.getDocumentFileOrDirOrNull(file, null, this.strategyID);
}

@Override
Expand Down Expand Up @@ -255,7 +255,8 @@ public long lastModified() {

@Override
public boolean mkdirs() {
this.androidFile = documentFileTranslator.getOrCreateDirectory(getFile());
this.androidFile = documentFileTranslator.getOrCreateDirectory(getFile(), strategyID);
invalidateParentDirCache();
return null != this.androidFile;
}

Expand Down Expand Up @@ -303,7 +304,7 @@ public OutputStream openOutputStream() throws FileNotFoundException {
DocumentFile androidFile = getAndroidFile(false);
String context = "openOutputStream overwrite existing ";
if (androidFile == null) {
final DocumentFile documentFileParent = documentFileTranslator.getOrCreateDirectory(getFile().getParentFile());
final DocumentFile documentFileParent = documentFileTranslator.getOrCreateDirectory(getFile().getParentFile(), strategyID);
androidFile = this.androidFile = documentFileParent.createFile(null, getFile().getName());
context = "openOutputStream create new ";
}
Expand Down Expand Up @@ -335,6 +336,14 @@ public InputStream openInputStream() throws FileNotFoundException {
return resultInputStream;
}

//------- file cache support for android
@Override
public void invalidateParentDirCache() {
if (documentFileTranslator != null)
documentFileTranslator.documentFileCache.invalidateParentDirCache(strategyID);
}


private IFile[] get(DocumentFile[] docs) {
AndroidFileFacade[] f = new AndroidFileFacade[docs.length];
final File parent = getFile();
Expand Down
91 changes: 91 additions & 0 deletions app/src/main/java/de/k3b/android/io/DocumentFileCache.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* Copyright (c) 2021 by k3b.
*
* This file is part of AndroFotoFinder / #APhotoManager.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>
*/
package de.k3b.android.io;

import android.support.v4.provider.DocumentFile;
import android.util.Log;

import java.io.File;
import java.util.HashMap;

import de.k3b.io.filefacade.IFile;
import de.k3b.media.PhotoPropertiesUtil;

public class DocumentFileCache {
private static final String TAG = DocumentFileTranslator.TAG;

private CurrentFileCache[] currentFileCaches = null;

/**
* strategyID : IFile.STRATEGY_XXX.
*/
public CurrentFileCache getCacheStrategy(int strategyID) {
if (currentFileCaches == null) {
currentFileCaches = new CurrentFileCache[IFile.STRATEGY_MAX + 1];
currentFileCaches[IFile.STRATEGY_INPUT] = new CurrentFileCache();
currentFileCaches[IFile.STRATEGY_OUTPUT] = new CurrentFileCache();
currentFileCaches[IFile.STRATEGY_NONE] = null;
}
if (strategyID >= 0 && strategyID < currentFileCaches.length) {
return currentFileCaches[strategyID];
}
Log.w(TAG, "DocumentFileCache.setCacheStrategy(id=" + strategyID +
") unknow Strategy");
return currentFileCaches[IFile.STRATEGY_NONE];
}

public DocumentFile findFile(DocumentFile parentDoc, File parentFile, String displayName, int strategyID) {
CurrentFileCache currentFileCache = getCacheStrategy(strategyID);

if (currentFileCache != null) {
if (!parentFile.equals(currentFileCache.lastParentFile)) {
currentFileCache.lastParentFile = parentFile;
currentFileCache.lastChildDocFiles.clear();
for (DocumentFile childDoc : parentDoc.listFiles()) {
if (childDoc.isFile()) {
String childDocName = childDoc.getName().toLowerCase();
if (PhotoPropertiesUtil.isImage(childDocName, PhotoPropertiesUtil.IMG_TYPE_ALL | PhotoPropertiesUtil.IMG_TYPE_XMP)) {
currentFileCache.lastChildDocFiles.put(childDocName, childDoc);
}
}
}

}

if (PhotoPropertiesUtil.isImage(displayName, PhotoPropertiesUtil.IMG_TYPE_ALL | PhotoPropertiesUtil.IMG_TYPE_XMP)) {
return currentFileCache.lastChildDocFiles.get(displayName.toLowerCase());
}
}
return parentDoc.findFile(displayName);
}

public void invalidateParentDirCache(int strategyID) {
CurrentFileCache currentFileCache = getCacheStrategy(strategyID);
if (currentFileCache != null) currentFileCache.lastParentFile = null;
}

/**
* Mapping from local file name inside lastParentFile to photo-related-DocumentFiles
*/
private static class CurrentFileCache {
private final HashMap<String, DocumentFile> lastChildDocFiles = new HashMap<>();
private File lastParentFile = null;
}

}
50 changes: 15 additions & 35 deletions app/src/main/java/de/k3b/android/io/DocumentFileTranslator.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 by k3b.
* Copyright (c) 2020-2021 by k3b.
*
* This file is part of AndroFotoFinder / #APhotoManager.
*
Expand Down Expand Up @@ -36,7 +36,6 @@
import java.util.Map;

import de.k3b.io.filefacade.FileFacade;
import de.k3b.media.PhotoPropertiesUtil;

/**
* Handles Translation from File to android specific DocumentFileUtils
Expand Down Expand Up @@ -67,12 +66,8 @@ public class DocumentFileTranslator {
* Mapping from known File to DocumentFile-Directory translation
*/
private final Map<File, DocumentFile> dirCache = new HashMap<>();
protected final DocumentFileCache documentFileCache = new DocumentFileCache();

/**
* Mapping from local file name inside lastParentFile to photo-related-DocumentFiles
*/
private final File lastParentFile = null;
private final HashMap<String, DocumentFile> lastChildDocFiles = new HashMap<>();

private static final File internalRootCandidate = new File("/storage/emulated/0");
// for debugging
Expand Down Expand Up @@ -181,21 +176,21 @@ public DocumentFileTranslator add(File directory, DocumentFile documentFileDir)
return this;
}

private DocumentFile getDocumentFileOrDirImpl(File fileOrDir, boolean isDir) {
private DocumentFile getDocumentFileOrDirImpl(File fileOrDir, boolean isDir, int strategyID) {
DocumentFile result = null;
if (fileOrDir != null) {
result = getFromCache(fileOrDir);
if (result == null) {
DocumentFile parent = getDocumentFileOrDirImpl(fileOrDir.getParentFile(), true);
DocumentFile parent = getDocumentFileOrDirImpl(fileOrDir.getParentFile(), true, strategyID);
if (parent != null) {
result = findFile(parent, fileOrDir, isDir);
result = findFile(parent, fileOrDir, isDir, strategyID);
}
}
}
return result;
}

private DocumentFile findFile(DocumentFile parentDoc, File fileOrDir, boolean isDir) {
private DocumentFile findFile(DocumentFile parentDoc, File fileOrDir, boolean isDir, int strategyID) {
String displayName = fileOrDir.getName();
File parentFile = fileOrDir.getParentFile();
if (isDir) {
Expand All @@ -214,23 +209,7 @@ private DocumentFile findFile(DocumentFile parentDoc, File fileOrDir, boolean is
}
return foundDoc;
} else {
if (!parentFile.equals(lastParentFile)) {
lastChildDocFiles.clear();
for (DocumentFile childDoc : parentDoc.listFiles()) {
if (childDoc.isFile()) {
String childDocName = childDoc.getName().toLowerCase();
if (PhotoPropertiesUtil.isImage(childDocName, PhotoPropertiesUtil.IMG_TYPE_ALL | PhotoPropertiesUtil.IMG_TYPE_XMP)) {
lastChildDocFiles.put(childDocName, childDoc);
}
}
}

}

if (PhotoPropertiesUtil.isImage(displayName, PhotoPropertiesUtil.IMG_TYPE_ALL | PhotoPropertiesUtil.IMG_TYPE_XMP)) {
return lastChildDocFiles.get(displayName.toLowerCase());
}
return parentDoc.findFile(fileOrDir.getName());
return documentFileCache.findFile(parentDoc, parentFile, displayName, strategyID);
}
}

Expand All @@ -239,14 +218,14 @@ private DocumentFile findFile(DocumentFile parentDoc, File fileOrDir, boolean is
*
* @return the found or created directory
*/
public DocumentFile getOrCreateDirectory(File directory) {
public DocumentFile getOrCreateDirectory(File directory, int strategyID) {
DocumentFile result = null;
if (directory != null) {
result = getFromCache(directory);
if (result == null) {
DocumentFile parent = getOrCreateDirectory(directory.getParentFile());
DocumentFile parent = getOrCreateDirectory(directory.getParentFile(), strategyID);
if ((parent != null) && parent.isDirectory()) {
result = findFile(parent, directory, true);
result = findFile(parent, directory, true, strategyID);

if (result == null) {
result = parent.createDirectory(directory.getName());
Expand All @@ -262,17 +241,18 @@ public DocumentFile getOrCreateDirectory(File directory) {
* gets existing DocumentFile that correspondws to fileOrDir
* or null if not exists or no write permissions
*
* @param fileOrDir where DocumentFile is searched for
* @param isDir if null: return null if isDir is matchning
* @param fileOrDir where DocumentFile is searched for
* @param isDir if null: return null if isDir is matchning
* @param strategyID
* @return DocumentFile or null
*/
public DocumentFile getDocumentFileOrDirOrNull(File fileOrDir, Boolean isDir) {
public DocumentFile getDocumentFileOrDirOrNull(File fileOrDir, Boolean isDir, int strategyID) {
DocumentFile result = null;
String path = fileOrDir != null ? fileOrDir.getAbsolutePath() : "";
final String context = FileFacade.debugLogFacade ? (mDebugPrefix + "getDocumentFile('"
+ path + "') ") : null;
try {
result = getDocumentFileOrDirImpl(fileOrDir, isDir == Boolean.TRUE);
result = getDocumentFileOrDirImpl(fileOrDir, isDir == Boolean.TRUE, strategyID);
if ((context != null) && (result == null)) {
Log.i(TAG, context + "not found");
}
Expand Down
1 change: 1 addition & 0 deletions fotolib2/src/main/java/de/k3b/media/ExifInterface.java
Original file line number Diff line number Diff line change
Expand Up @@ -1416,6 +1416,7 @@ public void saveAttributes(IFile inFile, IFile outFile,
if (overwriteOriginal) {
final String name = inFile.getName();
final String tempName = name + TMP_FILE_SUFFIX;
// inFile.setCacheStrategy(3); //!!!
inFile = renameSouraceFileBeforeReplaceOrThrow(inFile, tempName);

currentOutFile = outFile.getParentFile().create(name);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ public IFile convert(String dbgContext, File file) {

private File file;

protected int strategyID = 0;

private static final List<String> allowedFileSuffixesLowercase = new ArrayList<>();

static {
Expand Down Expand Up @@ -338,4 +340,19 @@ public File getFile() {
protected void setFile(File file) {
this.file = file;
}


/**
* true: forInput; false: forOutput; null: disable cache
*/
@Override
public int setCacheStrategy(int strategyID) {
int old = this.strategyID;
this.strategyID = strategyID;
return old;
}

@Override
public void invalidateParentDirCache() {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,16 @@ public long length() {
return child.length();
}

@Override
public int setCacheStrategy(int strategyID) {
return child.setCacheStrategy(strategyID);
}

@Override
public void invalidateParentDirCache() {
child.invalidateParentDirCache();
}

@Override
public boolean equals(Object o) {
return child.equals(o);
Expand Down
16 changes: 15 additions & 1 deletion libK3bFilefacade/src/main/java/de/k3b/io/filefacade/IFile.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,15 @@
* Goal: to become an android independant replacement for java.io.File
* that can be implemented by android independant de.k3b.io.File
* and android specific de.k3b.android.io....
*
* <p>
* This interface has the similar method names/sinatures as de.k3b.io.File
*/
public interface IFile {
int STRATEGY_INPUT = 0;
int STRATEGY_OUTPUT = 1;
int STRATEGY_NONE = 2;
int STRATEGY_MAX = STRATEGY_NONE;

void set(IFile src);

@Deprecated
Expand Down Expand Up @@ -95,4 +100,13 @@ public interface IFile {
File getFile();

long length();

//------- file cache support

/**
* 0: forInput; 1: forOutput; 3: disable cache.
*/
int setCacheStrategy(int strategyID);

void invalidateParentDirCache();
}
Original file line number Diff line number Diff line change
Expand Up @@ -232,4 +232,14 @@ public File getFile() {
public long length() {
return 0;
}

@Override
public int setCacheStrategy(int strategyID) {
return 0;
}

@Override
public void invalidateParentDirCache() {

}
}

0 comments on commit 4f8a3e4

Please sign in to comment.