Skip to content

Commit

Permalink
#173: mediascanner improvement
Browse files Browse the repository at this point in the history
  • Loading branch information
k3b committed Jul 2, 2020
1 parent e7c0d0e commit 792829c
Show file tree
Hide file tree
Showing 9 changed files with 247 additions and 121 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -561,7 +561,14 @@ public void onDestroy() {
}

private void destroyLoaderIfFinishing(String context) {
if ((loaderID != -1) && (getActivity() != null) && (getActivity().isFinishing())) {
if ((getActivity() != null) && (getActivity().isFinishing())) {
destroyLoader(context);
}
}

//!!! TODO destroyLoader for performance reasons while scanner is active to remove
private void destroyLoader(String context) {
if (loaderID != -1) {
getLoaderManager().destroyLoader(loaderID);
if ((Global.debugEnabled) && (mCurorLoader != null)) {
Log.d(Global.LOG_CONTEXT, mDebugPrefix + context + " - releasing mCurorLoader" +
Expand Down
179 changes: 109 additions & 70 deletions app/src/main/java/de/k3b/android/io/AndroidFileCommands.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.Toast;

import java.io.File;
Expand Down Expand Up @@ -383,32 +384,127 @@ public int deleteFiles(SelectedFiles fotos, IProgessListener progessListener) {
if ((nameCount == 0) || (nameCount == deleteCount)) {
// no delete file error so also delete media-items
QueryParameter where = new QueryParameter();
FotoSql.setWhereSelectionPks (where, fotos.toIdString());
FotoSql.setWhereSelectionPks(where, fotos.toIdString());

FotoSql.getMediaDBApi().deleteMedia("AndroidFileCommands.deleteFiles", where.toAndroidWhere(), null, true);
}
return deleteCount;
}

/**
* answer from "which directory to start scanner from"?
*/
private void onMediaScannerAnswer(Activity activity, IFile scanRootDir,
boolean fullScan, boolean rescanNeverScannedByAPM, boolean scanForDeleted) {
if ((AndroidFileCommands.canProcessFile(activity, this.isInBackground)) || (RecursivePhotoPropertiesMediaFilesScannerAsyncTask.sScanner == null)) {

// remove ".nomedia" file from scan root
IFile nomedia = scanRootDir.create(PhotoPropertiesMediaFilesScanner.MEDIA_IGNORE_FILENAME);
if (nomedia.exists()) {
if (Global.debugEnabled) {
Log.i(Global.LOG_CONTEXT, mDebugPrefix + "onMediaScannerAnswer deleting " + nomedia);
}
nomedia.delete();
}
if (Global.debugEnabled) {
Log.i(Global.LOG_CONTEXT, mDebugPrefix + "onMediaScannerAnswer start scanning " + scanRootDir);
}

final String message = activity.getString(R.string.scanner_menu_title);

final RecursivePhotoPropertiesMediaFilesScannerAsyncTask scanner = (RecursivePhotoPropertiesMediaFilesScannerAsyncTask.sScanner != null)
? RecursivePhotoPropertiesMediaFilesScannerAsyncTask.sScanner :
new RecursivePhotoPropertiesMediaFilesScannerAsyncTask(
mScanner, activity, message,
fullScan, rescanNeverScannedByAPM, scanForDeleted);
synchronized (this) {
if (RecursivePhotoPropertiesMediaFilesScannerAsyncTask.sScanner == null) {
RecursivePhotoPropertiesMediaFilesScannerAsyncTask.sScanner = scanner;
scanner.execute(new IFile[]{scanRootDir});
} // else scanner is already running
}

showMediaScannerStatus(RecursivePhotoPropertiesMediaFilesScannerAsyncTask.sScanner, activity);
}
}

public boolean cmdMediaScannerWithQuestion(Activity activity) {
final RecursivePhotoPropertiesMediaFilesScannerAsyncTask scanner = RecursivePhotoPropertiesMediaFilesScannerAsyncTask.sScanner;

if (scanner != null) {
// connect gui to already running scanner if possible
scanner.resumeIfNeccessary(); // if paused resume it.
showMediaScannerStatus(scanner, activity);
return true;
} else if (AndroidFileCommands.canProcessFile(activity, this.isInBackground)) {
// show dialog to get start parameter
MediaScannerDirectoryPickerFragment destDir = new MediaScannerDirectoryPickerFragment();

destDir.setParent(this);
destDir.setTitleId(R.string.scanner_dir_question);
destDir.defineDirectoryNavigation(OsUtils.getRootOSDirectory(null),
FotoSql.QUERY_TYPE_UNDEFINED,
getLastCopyToPath());
if (!LockScreen.isLocked(activity)) {
destDir.setContextMenuId(R.menu.menu_context_pick_osdir);
}

destDir.show(activity.getFragmentManager(), "scannerPick");

return true;
}
return false;
}

@SuppressLint("ValidFragment")
public static class MediaScannerDirectoryPickerFragment extends DirectoryPickerFragment {
private AndroidFileCommands mParent = null;
private CheckBox chkIncremental = null;
private CheckBox chkFullScan = null;
private CheckBox chkRescanNeverScannedByAPM = null;
private CheckBox chkScanForDeleted = null;

/** do not use activity callback */
@Override protected void setDirectoryListener(Activity activity) {}
/**
* do not use activity callback
*/
@Override
protected void setDirectoryListener(Activity activity) {
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View result = super.onCreateView(inflater,container,savedInstanceState);
View result = super.onCreateView(inflater, container, savedInstanceState);

chkFullScan = (CheckBox) result.findViewById(R.id.chkFullScan);
chkFullScan.setVisibility(View.VISIBLE);

chkIncremental = (CheckBox) result.findViewById(R.id.chkIncremental);
chkIncremental.setVisibility(View.VISIBLE);
chkRescanNeverScannedByAPM = (CheckBox) result.findViewById(R.id.chkRescanNeverScannedByAPM);
chkRescanNeverScannedByAPM.setVisibility(View.VISIBLE);

chkScanForDeleted = (CheckBox) result.findViewById(R.id.chkScanForDeleted);
chkScanForDeleted.setVisibility(View.VISIBLE);

chkFullScan.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (chkFullScan.isChecked() && chkRescanNeverScannedByAPM.isChecked()) {
chkRescanNeverScannedByAPM.setChecked(false);
}
}
});
chkRescanNeverScannedByAPM.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (chkFullScan.isChecked() && chkRescanNeverScannedByAPM.isChecked()) {
chkFullScan.setChecked(false);
}
}
});
final SharedPreferences preferences = PreferenceManager
.getDefaultSharedPreferences(getActivity());
chkIncremental.setChecked(preferences.getBoolean("scan-incremental", false));
chkFullScan.setChecked(preferences.getBoolean("chkFullScan", true));
chkRescanNeverScannedByAPM.setChecked(preferences.getBoolean("chkRescanNeverScannedByAPM", false));
chkScanForDeleted.setChecked(preferences.getBoolean("chkScanForDeleted", false));

return result;
}
Expand All @@ -418,13 +514,16 @@ protected void onDirectoryPick(IDirectory selection) {
if ((mParent != null) && (selection != null)) {
SharedPreferences.Editor prefs = PreferenceManager
.getDefaultSharedPreferences(getActivity()).edit();
prefs.putBoolean("scan-incremental", chkIncremental.isChecked());
prefs.putBoolean("chkFullScan", chkFullScan.isChecked());
prefs.putBoolean("chkRescanNeverScannedByAPM", chkRescanNeverScannedByAPM.isChecked());
prefs.putBoolean("chkScanForDeleted", chkScanForDeleted.isChecked());
prefs.apply();

mParent.onMediaScannerAnswer(
mContext,
FileFacade.convert("onDirectoryPick", selection.getAbsolute()),
chkIncremental.isChecked());
chkFullScan.isChecked(),
chkRescanNeverScannedByAPM.isChecked(), chkScanForDeleted.isChecked());
}
dismiss();
}
Expand Down Expand Up @@ -452,66 +551,6 @@ public void dismiss() {

}

public boolean cmdMediaScannerWithQuestion(Activity activity) {
final RecursivePhotoPropertiesMediaFilesScannerAsyncTask scanner = RecursivePhotoPropertiesMediaFilesScannerAsyncTask.sScanner;

if (scanner != null) {
// connect gui to already running scanner if possible
scanner.resumeIfNeccessary(); // if paused resume it.
showMediaScannerStatus(scanner, activity);
return true;
} else if (AndroidFileCommands.canProcessFile(activity, this.isInBackground)) {
// show dialog to get start parameter
MediaScannerDirectoryPickerFragment destDir = new MediaScannerDirectoryPickerFragment();

destDir.setParent(this);
destDir.setTitleId(R.string.scanner_dir_question);
destDir.defineDirectoryNavigation(OsUtils.getRootOSDirectory(null),
FotoSql.QUERY_TYPE_UNDEFINED,
getLastCopyToPath());
if (!LockScreen.isLocked(activity)) {
destDir.setContextMenuId(R.menu.menu_context_pick_osdir);
}

destDir.show(activity.getFragmentManager(), "scannerPick");

return true;
}
return false;
}

/** answer from "which directory to start scanner from"? */
private void onMediaScannerAnswer(Activity activity, IFile scanRootDir, boolean incremental) {
if ((AndroidFileCommands.canProcessFile(activity, this.isInBackground)) || (RecursivePhotoPropertiesMediaFilesScannerAsyncTask.sScanner == null)){

// remove ".nomedia" file from scan root
IFile nomedia = scanRootDir.create(PhotoPropertiesMediaFilesScanner.MEDIA_IGNORE_FILENAME);
if (nomedia.exists()) {
if (Global.debugEnabled) {
Log.i(Global.LOG_CONTEXT, mDebugPrefix + "onMediaScannerAnswer deleting " + nomedia);
}
nomedia.delete();
}
if (Global.debugEnabled) {
Log.i(Global.LOG_CONTEXT, mDebugPrefix + "onMediaScannerAnswer start scanning " + scanRootDir);
}

final String message = activity.getString(R.string.scanner_menu_title);

final RecursivePhotoPropertiesMediaFilesScannerAsyncTask scanner = (RecursivePhotoPropertiesMediaFilesScannerAsyncTask.sScanner != null)
? RecursivePhotoPropertiesMediaFilesScannerAsyncTask.sScanner :
new RecursivePhotoPropertiesMediaFilesScannerAsyncTask(mScanner, activity, message, incremental);
synchronized (this) {
if (RecursivePhotoPropertiesMediaFilesScannerAsyncTask.sScanner == null) {
RecursivePhotoPropertiesMediaFilesScannerAsyncTask.sScanner = scanner;
scanner.execute(new IFile[]{scanRootDir});
} // else scanner is already running
}

showMediaScannerStatus(RecursivePhotoPropertiesMediaFilesScannerAsyncTask.sScanner, activity);
}
}

private void showMediaScannerStatus(RecursivePhotoPropertiesMediaFilesScannerAsyncTask mediaScanner, Activity activity) {
if (mediaScanner != null) {
mediaScanner.showStatusDialog(activity);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,15 @@ abstract public class PhotoPropertiesMediaFilesScanner {
public static final int DEFAULT_SCAN_DEPTH = 22;
public static final String MEDIA_IGNORE_FILENAME = FileUtils.MEDIA_IGNORE_FILENAME; // MediaStore.MEDIA_IGNORE_FILENAME;

/** singelton */
/**
* singelton
*/
private static PhotoPropertiesMediaFilesScanner sInstance = null;

public final Context mContext;

private Map<String, Boolean> noMediaCache = new HashMap<>();

public PhotoPropertiesMediaFilesScanner(Context context) {
mContext = context.getApplicationContext();
}
Expand All @@ -122,15 +126,23 @@ public static boolean isNoMedia(int maxLevel, IFile[] pathNames) {
return false;
}

/** return true, if file is in a ".nomedia" dir */
public static boolean isNoMedia(IFile path, int maxLevel) {
return FileUtils.isNoMedia(path,maxLevel);
return isNoMedia(path, maxLevel, null);
}

/**
* return true, if file is in a ".nomedia" dir
*/
public static boolean isNoMedia(IFile path, int maxLevel, Map<String, Boolean> noMediaCache) {
return FileUtils.isNoMedia(path, maxLevel, noMediaCache);
}

/** return true, if file is in a ".nomedia" dir */
/**
* return true, if file is in a ".nomedia" dir
*/
@Deprecated
public static boolean isNoMedia(String path, int maxLevel) {
return FileUtils.isNoMedia(path,maxLevel);
return FileUtils.isNoMedia(path, maxLevel);
}

@Deprecated
Expand Down Expand Up @@ -208,7 +220,7 @@ private int excludeNomediaFiles(IFile[] fullPathNames) {
for (int i = 0; i < fullPathNames.length; i++) {
IFile fullPathName = fullPathNames[i];
if (fullPathName != null) {
if (!PhotoPropertiesUtil.isImage(fullPathName, PhotoPropertiesUtil.IMG_TYPE_ALL) || isNoMedia(fullPathName, 22)) {
if (!PhotoPropertiesUtil.isImage(fullPathName, PhotoPropertiesUtil.IMG_TYPE_ALL) || isNoMedia(fullPathName, 5, this.noMediaCache)) {
fullPathNames[i] = null;
} else {
itemsLeft++;
Expand Down Expand Up @@ -368,8 +380,6 @@ protected PhotoPropertiesMediaDBContentValues getExifFromFile(ContentValues valu
/** updates values with current values of file. */
protected PhotoPropertiesMediaDBContentValues getExifFromFile(ContentValues values, IFile jpgFile) {
try {
String absoluteJpgPath = jpgFile.getCanonicalPath();

BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true; // only need with/height but not content
BitmapFactory.decodeStream(jpgFile.openInputStream(), null, options);
Expand All @@ -391,7 +401,7 @@ protected PhotoPropertiesMediaDBContentValues getExifFromFile(ContentValues valu

TagSql.setXmpFileModifyDate(values, xmpFilelastModified);

IPhotoProperties exif = loadNonMediaValues(values, absoluteJpgPath, xmpContent);
IPhotoProperties exif = loadNonMediaValues(values, jpgFile, xmpContent);

IPhotoProperties src = null;
if (exif == null) {
Expand All @@ -411,6 +421,7 @@ protected PhotoPropertiesMediaDBContentValues getExifFromFile(ContentValues valu
updateTagRepository(src.getTags());
}

String absoluteJpgPath = jpgFile.getCanonicalPath();
setPathRelatedFieldsIfNeccessary(values, absoluteJpgPath, null);

return dest;
Expand Down Expand Up @@ -456,7 +467,7 @@ protected IGeoPointInfo getPositionFromMeta(String absoluteJpgPath, String id, I
return null;
}

abstract protected IPhotoProperties loadNonMediaValues(ContentValues destinationValues, String absoluteJpgPath, IPhotoProperties xmpContent);
abstract protected IPhotoProperties loadNonMediaValues(ContentValues destinationValues, IFile jpgFile, IPhotoProperties xmpContent);

/** @return number of copied properties */
protected int getExifValues(PhotoPropertiesMediaDBContentValues dest, IPhotoProperties src) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import java.io.IOException;

import de.k3b.geo.api.IGeoPointInfo;
import de.k3b.io.filefacade.IFile;
import de.k3b.media.ExifInterfaceEx;
import de.k3b.media.IPhotoProperties;

Expand All @@ -41,10 +42,10 @@ public PhotoPropertiesMediaFilesScannerExifInterface(Context context) {
}

@Override
protected IPhotoProperties loadNonMediaValues(ContentValues destinationValues, String absoluteJpgPath, IPhotoProperties xmpContent) {
protected IPhotoProperties loadNonMediaValues(ContentValues destinationValues, IFile jpgFile, IPhotoProperties xmpContent) {
ExifInterfaceEx exif = null;
try {
exif = ExifInterfaceEx.create(absoluteJpgPath, null, xmpContent, "PhotoPropertiesMediaFilesScannerExifInterface.loadNonMediaValues");
exif = ExifInterfaceEx.create(jpgFile, null, xmpContent, "PhotoPropertiesMediaFilesScannerExifInterface.loadNonMediaValues");
if (!exif.isValidJpgExifFormat()) exif = null;
} catch (IOException ex) {
// exif is null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

import de.k3b.geo.api.IGeoPointInfo;
import de.k3b.io.filefacade.FileFacade;
import de.k3b.io.filefacade.IFile;
import de.k3b.media.IPhotoProperties;
import de.k3b.media.PhotoPropertiesImageReader;

Expand All @@ -40,10 +41,10 @@ public PhotoPropertiesMediaFilesScannerImageMetaReader(Context context) {
}

@Override
protected IPhotoProperties loadNonMediaValues(ContentValues destinationValues, String absoluteJpgPath, IPhotoProperties xmpContent) {
protected IPhotoProperties loadNonMediaValues(ContentValues destinationValues, IFile jpgFile, IPhotoProperties xmpContent) {
PhotoPropertiesImageReader exif = null;
try {
exif = new PhotoPropertiesImageReader().load(FileFacade.convert("PhotoPropertiesMediaFilesScannerImageMetaReader loadNonMediaValues", absoluteJpgPath), null, xmpContent, "PhotoPropertiesMediaFilesScannerImageMetaReader load");
exif = new PhotoPropertiesImageReader().load(jpgFile, null, xmpContent, "PhotoPropertiesMediaFilesScannerImageMetaReader load");
} catch (IOException ex) {
// exif is null
}
Expand Down
Loading

0 comments on commit 792829c

Please sign in to comment.