diff --git a/app/src/main/java/de/k3b/android/androFotoFinder/FotoGalleryActivity.java b/app/src/main/java/de/k3b/android/androFotoFinder/FotoGalleryActivity.java
index 0b8b95e2..c3a5a45d 100644
--- a/app/src/main/java/de/k3b/android/androFotoFinder/FotoGalleryActivity.java
+++ b/app/src/main/java/de/k3b/android/androFotoFinder/FotoGalleryActivity.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2020 by k3b.
+ * Copyright (c) 2015-2021 by k3b.
*
* This file is part of AndroFotoFinder / #APhotoManager.
*
@@ -208,6 +208,9 @@ public boolean onOptionsItemSelected(MenuItem item) {
case R.id.cmd_db_reload:
AndroFotoFinderApp.getMediaContent2DbUpdateService().rebuild(this, null);
return true;
+ case R.id.cmd_db_update:
+ AndroFotoFinderApp.getMediaContent2DbUpdateService().update(this, null);
+ return true;
case R.id.cmd_more:
new Handler().postDelayed(new Runnable() {
public void run() {
diff --git a/app/src/main/java/de/k3b/android/androFotoFinder/queries/FotoSql.java b/app/src/main/java/de/k3b/android/androFotoFinder/queries/FotoSql.java
index bce4ace5..9e72a8f8 100644
--- a/app/src/main/java/de/k3b/android/androFotoFinder/queries/FotoSql.java
+++ b/app/src/main/java/de/k3b/android/androFotoFinder/queries/FotoSql.java
@@ -178,6 +178,11 @@ public class FotoSql extends FotoSqlBase {
// SQL_COL_LAST_MODIFIED in seconds since 1970; "?" in milli-seconds since 1970
private static final String FILTER_EXPR_DATE_MODIFIED_MAX = SQL_COL_LAST_MODIFIED + " < ?";
private static final String FILTER_EXPR_DATE_MODIFIED_MIN = SQL_COL_LAST_MODIFIED + " >= ?";
+
+ // SQL_COL_DATE_ADDED in seconds since 1970; "?" in milli-seconds since 1970
+ private static final String FILTER_EXPR_DATE_ADDED_MAX = SQL_COL_DATE_ADDED + " < ?";
+ private static final String FILTER_EXPR_DATE_ADDED_MIN = SQL_COL_DATE_ADDED + " >= ?";
+
protected static final String FILTER_EXPR_PATH_LIKE = "(" + SQL_COL_PATH + " like ?)";
// same format as dir. i.e. description='/2014/12/24/' or '/mnt/sdcard/pictures/'
@@ -405,12 +410,26 @@ public static void addWhereDateMinMax(QueryParameter resultQuery, final long dat
public static void addWhereDateModifiedMinMax(QueryParameter resultQuery, final long dateMinInMilliSecs1970, final long dateMaxInMilliSecs1970) {
// SQL_COL_LAST_MODIFIED in seconds since 1970; translate from MilliSecs
- if (dateMinInMilliSecs1970 != 0) resultQuery.addWhere(FILTER_EXPR_DATE_MODIFIED_MIN, Long.toString(dateMinInMilliSecs1970 / LAST_MODIFIED_FACTOR));
+ if (dateMinInMilliSecs1970 != 0)
+ resultQuery.addWhere(FILTER_EXPR_DATE_MODIFIED_MIN, Long.toString(dateMinInMilliSecs1970 / LAST_MODIFIED_FACTOR));
+
+ if (dateMaxInMilliSecs1970 != 0)
+ resultQuery.addWhere(FILTER_EXPR_DATE_MODIFIED_MAX, Long.toString(dateMaxInMilliSecs1970 / LAST_MODIFIED_FACTOR));
+ }
- if (dateMaxInMilliSecs1970 != 0) resultQuery.addWhere(FILTER_EXPR_DATE_MODIFIED_MAX, Long.toString(dateMaxInMilliSecs1970 / LAST_MODIFIED_FACTOR));
+ public static void addWhereDateAddedMinMax(QueryParameter resultQuery, final long dateMinInMilliSecs1970, final long dateMaxInMilliSecs1970) {
+
+ // SQL_COL_DATE_ADDED in seconds since 1970; translate from MilliSecs
+ if (dateMinInMilliSecs1970 != 0)
+ resultQuery.addWhere(FILTER_EXPR_DATE_ADDED_MIN, Long.toString(dateMinInMilliSecs1970 / LAST_MODIFIED_FACTOR));
+
+ if (dateMaxInMilliSecs1970 != 0)
+ resultQuery.addWhere(FILTER_EXPR_DATE_ADDED_MAX, Long.toString(dateMaxInMilliSecs1970 / LAST_MODIFIED_FACTOR));
}
- /** translates a query back to filter */
+ /**
+ * translates a query back to filter
+ */
public static IGalleryFilter parseQuery(QueryParameter query, boolean removeFromSourceQuery) {
if (query != null) {
GalleryFilterParameter filter = new GalleryFilterParameter();
diff --git a/app/src/main/java/de/k3b/android/androFotoFinder/queries/MediaContent2DBUpdateService.java b/app/src/main/java/de/k3b/android/androFotoFinder/queries/MediaContent2DBUpdateService.java
index a663a295..b40c5094 100644
--- a/app/src/main/java/de/k3b/android/androFotoFinder/queries/MediaContent2DBUpdateService.java
+++ b/app/src/main/java/de/k3b/android/androFotoFinder/queries/MediaContent2DBUpdateService.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019-2020 by k3b.
+ * Copyright (c) 2019-2021 by k3b.
*
* This file is part of AndroFotoFinder / #APhotoManager.
*
@@ -29,7 +29,7 @@
import de.k3b.io.IProgessListener;
/**
- * #155: takes care that chages from
+ * #155: takes care that changes from
* {@link MediaContentproviderRepository} are transfered to {@link MediaDBRepository}
*/
public class MediaContent2DBUpdateService {
@@ -60,11 +60,21 @@ public void clearMediaCopy() {
public void rebuild(Context context, IProgessListener progessListener) {
long start = new Date().getTime();
clearMediaCopy();
- MediaDBRepository.Impl.updateMediaCopy(context, writableDatabase, null, progessListener);
+ MediaDBRepository.Impl.updateMediaCopy(context, writableDatabase, null, null, progessListener);
start = (new Date().getTime() - start) / 1000;
final String text = "load db " + start + " secs";
Toast.makeText(context, text, Toast.LENGTH_LONG).show();
if (progessListener != null) progessListener.onProgress(0, 0, text);
+
+ }
+
+ public void update(Context context, IProgessListener progessListener) {
+ long start = new Date().getTime();
+ MediaDBRepository.Impl.updateMediaCopy(context, writableDatabase, progessListener);
+ start = (new Date().getTime() - start) / 1000;
+ final String text = "update db " + start + " secs";
+ Toast.makeText(context, text, Toast.LENGTH_LONG).show();
+ if (progessListener != null) progessListener.onProgress(0, 0, text);
}
diff --git a/app/src/main/java/de/k3b/android/androFotoFinder/queries/MediaDBRepository.java b/app/src/main/java/de/k3b/android/androFotoFinder/queries/MediaDBRepository.java
index 3c97778b..44faa632 100644
--- a/app/src/main/java/de/k3b/android/androFotoFinder/queries/MediaDBRepository.java
+++ b/app/src/main/java/de/k3b/android/androFotoFinder/queries/MediaDBRepository.java
@@ -20,6 +20,7 @@
import android.content.ContentValues;
import android.content.Context;
+import android.content.SharedPreferences;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.database.sqlite.SQLiteDatabase;
@@ -27,10 +28,12 @@
import android.net.Uri;
import android.os.Build;
import android.os.CancellationSignal;
+import android.preference.PreferenceManager;
import android.provider.MediaStore;
import android.util.Log;
import java.sql.Date;
+import java.util.Calendar;
import de.k3b.LibGlobal;
import de.k3b.android.androFotoFinder.Global;
@@ -86,7 +89,9 @@ public MediaDBRepository(SQLiteDatabase db) {
public Cursor createCursorForQuery(StringBuilder out_debugMessage, String dbgContext,
QueryParameter parameters, VISIBILITY visibility,
CancellationSignal cancellationSignal) {
- if (visibility != null) FotoSql.setWhereVisibility(parameters, visibility);
+ if (visibility != null) {
+ FotoSql.setWhereVisibility(parameters, visibility);
+ }
return createCursorForQuery(out_debugMessage, dbgContext,
parameters.toWhere(), parameters.toAndroidParameters(),
parameters.toGroupBy(), parameters.toHaving(),
@@ -475,6 +480,7 @@ public static class Impl {
.addColumn(USED_MEDIA_COLUMNS)
.addFrom(SQL_TABLE_EXTERNAL_CONTENT_URI_FILE_NAME)
.addWhere(FILTER_EXPR_AFFECTED_FILES);
+ private static long nextMonthTimeInSecs;
private static boolean isLomg(int index) {
return index >= intMin && index <= intMax;
@@ -517,7 +523,7 @@ private static String getSqlUpdateWithParams() {
return sql.toString();
}
- private static int bindAndExecUpdate(Cursor c, SQLiteStatement sql) {
+ private static int bindAndExecUpdate(Cursor c, SQLiteStatement sql, long dateAdded, long dateUpdated) {
sql.clearBindings();
// sql where
@@ -538,10 +544,16 @@ private static int bindAndExecUpdate(Cursor c, SQLiteStatement sql) {
sql.bindDouble(i, c.getDouble(i));
}
}
+ if (dateAdded != 0) {
+ sql.bindLong(colDATE_ADDED, dateAdded);
+ }
+ if (dateUpdated != 0) {
+ sql.bindLong(colLAST_MODIFIED, dateUpdated);
+ }
return sql.executeUpdateDelete();
}
- private static void bindAndExecInsert(Cursor c, SQLiteStatement sql) {
+ private static void bindAndExecInsert(Cursor c, SQLiteStatement sql, long dateAdded, long dateUpdated) {
sql.clearBindings();
for (int i = intMin; i <= intMax; i++) {
@@ -559,6 +571,12 @@ private static void bindAndExecInsert(Cursor c, SQLiteStatement sql) {
sql.bindDouble(i + 1, c.getDouble(i));
}
}
+ if (dateAdded != 0) {
+ sql.bindLong(colDATE_ADDED + 1, dateAdded);
+ }
+ if (dateUpdated != 0) {
+ sql.bindLong(colLAST_MODIFIED + 1, dateUpdated);
+ }
sql.executeInsert();
}
@@ -590,19 +608,37 @@ public static void clearMedaiCopy(SQLiteDatabase db) {
}
}
+ public static int updateMediaCopy(
+ Context context, SQLiteDatabase db,
+ IProgessListener progessListener) {
+ SharedPreferences prefsInstance = PreferenceManager
+ .getDefaultSharedPreferences(context.getApplicationContext());
+ long maxDateAddedSecs = prefsInstance.getLong("maxDateAddedSecs", 0l);
+ return updateMediaCopy(context, db, null, new Date(maxDateAddedSecs), progessListener);
+ }
- public static int updateMediaCopy(Context context, SQLiteDatabase db, Date lastUpdate, IProgessListener progessListener) {
+ public static int updateMediaCopy(
+ Context context, SQLiteDatabase db,
+ Date filterLastUpdateMin, Date filterLastAddedMin, IProgessListener progessListener) {
int progress = 0;
java.util.Date startTime = new java.util.Date();
- QueryParameter query = queryGetAllColumns;
- long _lastUpdate = (lastUpdate != null) ? (lastUpdate.getTime() / 1000L) : 0L;
+ QueryParameter query = new QueryParameter().getFrom(queryGetAllColumns);
- if (_lastUpdate != 0) {
- query = new QueryParameter().getFrom(queryGetAllColumns);
- FotoSql.addWhereDateModifiedMinMax(query, _lastUpdate, 0);
- // FotoSql.createCursorForQuery()
+ Calendar nextMonth = Calendar.getInstance();
+ nextMonth.add(Calendar.MONTH, 1);
+ nextMonthTimeInSecs = nextMonth.getTimeInMillis() / 1000;
+
+ long filterLastUpdateMinInMillis = (filterLastUpdateMin != null) ? (filterLastUpdateMin.getTime()) : 0L;
+ if (filterLastUpdateMinInMillis != 0) {
+ FotoSql.addWhereDateModifiedMinMax(query, filterLastUpdateMinInMillis, 0);
+ }
+
+ long filterLastAddedMinInMillis = (filterLastAddedMin != null) ? (filterLastAddedMin.getTime()) : 0L;
+ if (filterLastAddedMinInMillis != 0) {
+ FotoSql.addWhereDateAddedMinMax(query, filterLastAddedMinInMillis, nextMonth.getTimeInMillis());
}
+
Cursor c = null;
SQLiteStatement sqlInsert = null;
SQLiteStatement sqlUpdate = null;
@@ -611,7 +647,7 @@ public static int updateMediaCopy(Context context, SQLiteDatabase db, Date lastU
int itemCount = 0;
int insertCout = 0;
int updateCount = 0;
- // ContentValues contentValues = new ContentValues();
+
try {
db.beginTransaction(); // Performance boost: all db-inserts/updates in one transaction
@@ -624,26 +660,36 @@ public static int updateMediaCopy(Context context, SQLiteDatabase db, Date lastU
sqlInsert = db.compileStatement(getSqlInsertWithParams());
sqlUpdate = db.compileStatement(getSqlUpdateWithParams());
+ long maxDateAddedSecs = 0;
+ long maxDateUpdatedSecs = 0;
while (c.moveToNext()) {
- // getContentValues(c, contentValues);
- isUpdate = (c.getLong(colDATE_ADDED) <= _lastUpdate);
+ long curDateAddedSecs = getDateInSecs(c, colDATE_ADDED);
+ if (curDateAddedSecs > maxDateAddedSecs) {
+ maxDateAddedSecs = curDateAddedSecs;
+ }
+ isUpdate = (curDateAddedSecs <= filterLastUpdateMinInMillis / 1000);
+
+ long curDateUpdatedSecs = getDateInSecs(c, colLAST_MODIFIED);
+ if (curDateUpdatedSecs > maxDateUpdatedSecs) {
+ maxDateUpdatedSecs = curDateUpdatedSecs;
+ }
if (isUpdate) {
updateCount++;
lastSql = sqlUpdate;
- isUpdate = bindAndExecUpdate(c, sqlUpdate) > 0;
+ isUpdate = bindAndExecUpdate(c, sqlUpdate, curDateAddedSecs, curDateUpdatedSecs) > 0;
// 0 affected update rows: must insert
}
if (!isUpdate) {
insertCout++;
lastSql = sqlInsert;
- bindAndExecInsert(c, sqlInsert);
+ bindAndExecInsert(c, sqlInsert, curDateAddedSecs, curDateUpdatedSecs);
}
lastSql = null;
- // save(db, c, contentValues, _lastUpdate);
+
if ((progessListener != null) && (progress % 100) == 0) {
if (!progessListener.onProgress(progress, itemCount, context.getString(R.string.scanner_update_result_format, progress))) {
// canceled in gui thread
@@ -651,8 +697,11 @@ public static int updateMediaCopy(Context context, SQLiteDatabase db, Date lastU
}
}
progress++;
- }
+ } // while over all old items
db.setTransactionSuccessful(); // This commits the transaction if there were no exceptions
+
+ saveStats(context, maxDateAddedSecs, maxDateUpdatedSecs);
+
if (Global.debugEnabledSql) {
java.util.Date endTime = new java.util.Date();
final String message = "MediaDBRepository.updateMedaiCopy(inserted:" + insertCout +
@@ -685,6 +734,25 @@ public static int updateMediaCopy(Context context, SQLiteDatabase db, Date lastU
return progress;
}
+ private static void saveStats(Context context, long maxDateAddedSecs, long maxDateUpdatedSecs) {
+ SharedPreferences prefsInstance = PreferenceManager
+ .getDefaultSharedPreferences(context.getApplicationContext());
+
+ SharedPreferences.Editor prefs = prefsInstance.edit();
+ if (maxDateUpdatedSecs > 0) prefs.putLong("maxDateUpdatedSecs", maxDateUpdatedSecs + 1);
+ if (maxDateAddedSecs > 0) prefs.putLong("maxDateAddedSecs", maxDateAddedSecs + 1);
+ prefs.apply();
+ }
+
+ protected static long getDateInSecs(Cursor c, int colPosition) {
+ long curDateAdded = (c.isNull(colPosition)) ? 0 : c.getLong(colPosition);
+ if (curDateAdded > nextMonthTimeInSecs) {
+ // colDATE_ADDED: some apps/libs use milliscs instead of secs. Fix this.
+ curDateAdded = curDateAdded / 1000;
+ }
+ return curDateAdded;
+ }
+
private static void save(SQLiteDatabase db, Cursor c, ContentValues contentValues, long lastUpdate) {
boolean isNew = (c.getLong(colDATE_ADDED) > lastUpdate);
diff --git a/app/src/main/res/menu/menu_ao10.xml b/app/src/main/res/menu/menu_ao10.xml
index f2749423..d8748856 100644
--- a/app/src/main/res/menu/menu_ao10.xml
+++ b/app/src/main/res/menu/menu_ao10.xml
@@ -7,4 +7,10 @@
android:title="@string/load_db_menu_title"
android:visible="true" />
+
\ No newline at end of file
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index 1e1e6dfd..cb1e9ff1 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -242,6 +242,7 @@ Verstecken kann über das \'Media-Scanner\' Gallery-Menü rückgängig gemacht w
Dunkel
Mediendatenbank (neu) laden
+ Mediendatenbank aktualisieren
Fehlende Berechtigung
Benötigt Verzeichnisberechtigungen.
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index f41a2453..4a442243 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -287,6 +287,7 @@ You can undo hiding by calling the mediascanner from gallery-menu."
(Re)Load Media Database
+ Update Media Database
Missing permisions