From 402accbe29d96e89592e2b5d27f80c935a1cf31e Mon Sep 17 00:00:00 2001 From: k3b <1374583+k3b@users.noreply.github.com> Date: Mon, 12 Apr 2021 17:58:29 +0200 Subject: [PATCH] #155: ImageDetailMetaDialogBuilder more diagnostic support: Exif-Info from localDB and from contentProvider; Copy2Clipboard --- .../PhotoAutoprocessingEditActivity.java | 2 +- .../directory/DirectoryPickerFragment.java | 2 +- .../ImageDetailMetaDialogBuilder.java | 146 +++++++++++------- .../queries/IMediaRepositoryApi.java | 8 +- .../MediaContentproviderRepository.java | 6 +- .../MediaContentproviderRepositoryImpl.java | 44 ++++-- .../queries/MediaDBRepository.java | 42 +++-- .../queries/MediaRepositoryApiWrapper.java | 8 +- .../queries/MergedMediaRepository.java | 6 + .../de/k3b/android/io/AndroidFileFacade.java | 9 ++ .../de/k3b/android/util/ClipboardUtil.java | 6 +- 11 files changed, 181 insertions(+), 98 deletions(-) diff --git a/app/src/main/java/de/k3b/android/androFotoFinder/PhotoAutoprocessingEditActivity.java b/app/src/main/java/de/k3b/android/androFotoFinder/PhotoAutoprocessingEditActivity.java index 78705eda..8597690d 100644 --- a/app/src/main/java/de/k3b/android/androFotoFinder/PhotoAutoprocessingEditActivity.java +++ b/app/src/main/java/de/k3b/android/androFotoFinder/PhotoAutoprocessingEditActivity.java @@ -712,7 +712,7 @@ public boolean onOptionsItemSelected(MenuItem item) { return true; case android.R.id.copy: - return ClipboardUtil.addDirToClipboard(this, mCurrentOutDir.getAbsolutePath()); + return ClipboardUtil.addDirToClipboard(this, mCurrentOutDir.getAbsolutePath(), true); case android.R.id.paste: return onPaste(); default: diff --git a/app/src/main/java/de/k3b/android/androFotoFinder/directory/DirectoryPickerFragment.java b/app/src/main/java/de/k3b/android/androFotoFinder/directory/DirectoryPickerFragment.java index a3bef6ee..6e3f077e 100644 --- a/app/src/main/java/de/k3b/android/androFotoFinder/directory/DirectoryPickerFragment.java +++ b/app/src/main/java/de/k3b/android/androFotoFinder/directory/DirectoryPickerFragment.java @@ -462,7 +462,7 @@ public void notifyPhotoChanged() { private boolean onCopy(IDirectory selection) { String path = (selection == null) ? null : selection.getAbsolute(); - return ClipboardUtil.addDirToClipboard(this.getActivity(), path); + return ClipboardUtil.addDirToClipboard(this.getActivity(), path, true); } private boolean onEditApm(MenuItem menuItem, IDirectory selection) { diff --git a/app/src/main/java/de/k3b/android/androFotoFinder/imagedetail/ImageDetailMetaDialogBuilder.java b/app/src/main/java/de/k3b/android/androFotoFinder/imagedetail/ImageDetailMetaDialogBuilder.java index 6110124a..42571218 100644 --- a/app/src/main/java/de/k3b/android/androFotoFinder/imagedetail/ImageDetailMetaDialogBuilder.java +++ b/app/src/main/java/de/k3b/android/androFotoFinder/imagedetail/ImageDetailMetaDialogBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2020 by k3b. + * Copyright (c) 2015-2021 by k3b. * * This file is part of AndroFotoFinder. * @@ -23,6 +23,7 @@ import android.app.AlertDialog; import android.app.Dialog; import android.content.ContentValues; +import android.content.DialogInterface; import android.net.Uri; import android.widget.ScrollView; import android.widget.TextView; @@ -33,8 +34,11 @@ import java.util.Date; import java.util.List; -import de.k3b.android.androFotoFinder.queries.MediaContentproviderRepositoryImpl; +import de.k3b.android.androFotoFinder.R; +import de.k3b.android.androFotoFinder.queries.FotoSql; +import de.k3b.android.androFotoFinder.queries.IMediaRepositoryApi; import de.k3b.android.androFotoFinder.tagDB.TagSql; +import de.k3b.android.util.ClipboardUtil; import de.k3b.android.widget.ActivityWithCallContext; import de.k3b.database.QueryParameter; import de.k3b.io.DateUtil; @@ -76,13 +80,36 @@ public static Dialog createImageDetailDialog(Activity context, IFile file, Uri i return createImageDetailDialog(context, fileId.toString(), result.toString()); } - public static Dialog createImageDetailDialog(Activity context, String title, String block, Object... moreBlocks) { + private static final String line = "------------------"; + + private static void appendQueryInfo(StringBuilder result, QueryParameter query, long offset) { + if (query != null) { + result.append(NL).append(line).append(NL); + result.append(NL).append("#").append(offset).append(": ").append(query.toSqlString()).append(NL).append(NL); + } + } + + private static void append(StringBuilder result, String block) { + if (block != null) { + result.append(NL).append(line).append(NL); + result.append(NL).append(block).append(NL); + } + } + + private static final String dateFields = ("," + + TagSql.SQL_COL_DATE_ADDED + "," + + TagSql.SQL_COL_EXT_XMP_LAST_MODIFIED_DATE + "," + + TagSql.SQL_COL_LAST_MODIFIED + + ",").toLowerCase(); + + public static Dialog createImageDetailDialog(final Activity context, String title, String block, Object... moreBlocks) { AlertDialog.Builder builder = new AlertDialog.Builder(context); builder.setTitle(title); ScrollView sv = new ScrollView(context); sv.setVerticalScrollBarEnabled(true); - TextView view = new TextView(context); + final TextView view = new TextView(context); + view.setId(R.id.action_details); StringBuilder result = new StringBuilder(block); if ((moreBlocks != null) && (moreBlocks.length > 0)) { @@ -106,61 +133,33 @@ public void onClick(DialogInterface dialog, int id) { } });*/ - return builder.create(); - } - - private static void appendQueryInfo(StringBuilder result, QueryParameter query, long offset) { - if (query != null) { - result.append(NL).append(line).append(NL); - result.append(NL).append("#").append(offset).append(": ").append(query.toSqlString()).append(NL).append(NL); - } - } + builder.setNeutralButton(android.R.string.copy, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + ClipboardUtil.addDirToClipboard(context, view.getText(), false); + } + }); - private static void append(StringBuilder result, String block) { - if (block != null) { - result.append(NL).append(line).append(NL); - result.append(NL).append(block).append(NL); - } + return builder.create(); } - private static final String dateFields = ("," - + TagSql.SQL_COL_DATE_ADDED + "," - + TagSql.SQL_COL_EXT_XMP_LAST_MODIFIED_DATE + "," - + TagSql.SQL_COL_LAST_MODIFIED - + ",").toLowerCase(); - private static void appendExifInfo(Activity context, StringBuilder result, IFile jpegFile, Uri imageUri, long currentImageId) { try { - getExifInfo_android(context, result, jpegFile, imageUri); + appendExifInfoFromFile_android(context, result, jpegFile, imageUri); - addExif(context, result, jpegFile, imageUri); + appendExifFromFile_drewnoakes(context, result, jpegFile, imageUri); if (jpegFile != null) { // #84 show long and short xmp file - addXmp(result, XmpFile.getSidecar(jpegFile, true)); - addXmp(result, XmpFile.getSidecar(jpegFile, false)); + appendXmpFromFile(result, XmpFile.getSidecar(jpegFile, true)); + appendXmpFromFile(result, XmpFile.getSidecar(jpegFile, false)); } - if (currentImageId != 0) { - - ContentValues dbContent = MediaContentproviderRepositoryImpl.getDbContent(context, currentImageId); - if (dbContent != null) { - result.append(NL).append(line).append(NL); - result.append(NL).append(TagSql.SQL_TABLE_EXTERNAL_CONTENT_URI_FILE).append(NL).append(NL); - // sort by keys - List sortedKeys = new ArrayList(dbContent.keySet()); - Collections.sort(sortedKeys); - for (String key : sortedKeys) { - Object value = dbContent.get(key); - String sValue = (value != null) ? value.toString() : null; - if ((sValue != null) && (sValue.length() > 0) && (sValue.compareTo("0") != 0)) { - // show only non empty values - result.append(key).append("=").append(sValue); - appendDate(result, key, value); - result.append(NL); - } - } - } + if (currentImageId != 0 || jpegFile != null) { + String filePathOrNull = jpegFile != null ? jpegFile.getCanonicalPath() : null; + appendDbInfo(result, FotoSql.getMediaLocalDatabase(), currentImageId, filePathOrNull, + "LocalDatabase"); + appendDbInfo(result, FotoSql.getMediaDBApi(), currentImageId, filePathOrNull, + TagSql.SQL_TABLE_EXTERNAL_CONTENT_URI_FILE_NAME); } } catch (IOException e) { @@ -188,9 +187,34 @@ private static void appendDate(StringBuilder result, Object value, int factor) { } } - private static String line = "------------------"; + private static void appendDbInfo(StringBuilder result, IMediaRepositoryApi api, long currentImageId, String filePathOrNull, String callContext) { + if (api != null) { + result.append(NL).append(line).append(NL); + + String search = callContext + "(id=" + currentImageId + ", path='" + filePathOrNull + "')"; + ContentValues dbContent = api.getDbContent(currentImageId, filePathOrNull); + if (dbContent != null) { + appendFileMessage(result, search, NL); + // sort by keys + List sortedKeys = new ArrayList(dbContent.keySet()); + Collections.sort(sortedKeys); + for (String key : sortedKeys) { + Object value = dbContent.get(key); + String sValue = (value != null) ? value.toString() : null; + if ((sValue != null) && (sValue.length() > 0) && (sValue.compareTo("0") != 0)) { + // show only non empty values + result.append(key).append("=").append(sValue); + appendDate(result, key, value); + result.append(NL); + } + } + } else { + appendFileNotFoundMessage(result, search); + } + } + } - private static void addExif(Activity context, StringBuilder builder, IFile file, Uri imageUri) throws IOException { + private static void appendExifFromFile_drewnoakes(Activity context, StringBuilder builder, IFile file, Uri imageUri) throws IOException { PhotoPropertiesImageReader meta = null; Object fileId = file; if (file != null && file.exists()) { @@ -206,28 +230,28 @@ private static void addExif(Activity context, StringBuilder builder, IFile file, } if (meta != null) { - builder.append(NL).append(fileId).append(NL).append(NL); + appendFileMessage(builder, fileId, NL); builder.append(meta.toString()); builder.append(NL).append(line).append(NL); } else { - builder.append(NL).append(fileId).append(" not found.").append(NL); + appendFileNotFoundMessage(builder, fileId); } } - private static void addXmp(StringBuilder builder, IFile file) throws IOException { + private static void appendXmpFromFile(StringBuilder builder, IFile file) throws IOException { if (file.exists()) { XmpSegment meta = new XmpSegment(); meta.load(file.openInputStream(), "ImageDetailMetaDialogBuilder"); - builder.append(NL).append(file).append(NL).append(NL); + appendFileMessage(builder, file, NL); meta.appendXmp(null, builder); builder.append(NL).append(line).append(NL); } else { - builder.append(NL).append(file).append(" not found.").append(NL); + appendFileNotFoundMessage(builder, file); } } - private static void getExifInfo_android(Activity context, StringBuilder builder, IFile filepath, Uri imageUri) throws IOException { + private static void appendExifInfoFromFile_android(Activity context, StringBuilder builder, IFile filepath, Uri imageUri) throws IOException { Object fileId = filepath; ExifInterfaceEx exif = null; if (filepath != null && filepath.exists()) { @@ -243,10 +267,18 @@ private static void getExifInfo_android(Activity context, StringBuilder builder, if (exif != null) { builder.append(NL).append(line).append(NL); - builder.append(NL).append(fileId).append(NL).append(NL); + appendFileMessage(builder, fileId, NL); if (exif.isValidJpgExifFormat()) builder.append(exif.getDebugString(NL)); builder.append(NL).append(line).append(NL); } } + + private static void appendFileNotFoundMessage(StringBuilder builder, Object file) { + appendFileMessage(builder, file, " not found."); + } + + private static void appendFileMessage(StringBuilder builder, Object file, String message) { + builder.append(NL).append(file).append(message).append(NL); + } } diff --git a/app/src/main/java/de/k3b/android/androFotoFinder/queries/IMediaRepositoryApi.java b/app/src/main/java/de/k3b/android/androFotoFinder/queries/IMediaRepositoryApi.java index 7807600f..70e3a526 100644 --- a/app/src/main/java/de/k3b/android/androFotoFinder/queries/IMediaRepositoryApi.java +++ b/app/src/main/java/de/k3b/android/androFotoFinder/queries/IMediaRepositoryApi.java @@ -63,7 +63,13 @@ Long insertOrUpdateMediaDatabase(String dbgContext, */ int deleteMedia(String dbgContext, String where, String[] selectionArgs, boolean preventDeleteImageFile); - ContentValues getDbContent(long id); + /** + * get all column values belonging to id or filepath for debugging purpose + * + * @param idOrNull + * @param filePathOrNull + */ + ContentValues getDbContent(Long idOrNull, String filePathOrNull); long getCurrentUpdateId(); diff --git a/app/src/main/java/de/k3b/android/androFotoFinder/queries/MediaContentproviderRepository.java b/app/src/main/java/de/k3b/android/androFotoFinder/queries/MediaContentproviderRepository.java index 5826f161..1f2e62ed 100644 --- a/app/src/main/java/de/k3b/android/androFotoFinder/queries/MediaContentproviderRepository.java +++ b/app/src/main/java/de/k3b/android/androFotoFinder/queries/MediaContentproviderRepository.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2020 by k3b. + * Copyright (c) 2019-2021 by k3b. * * This file is part of AndroFotoFinder / #APhotoManager. * @@ -182,8 +182,8 @@ public int deleteMedia(String dbgContext, String sqlWhere, String[] selectionArg } @Override - public ContentValues getDbContent(final long id) { - return MediaContentproviderRepositoryImpl.getDbContent(context, id); + public ContentValues getDbContent(final Long idOrNull, String filePathOrNull) { + return MediaContentproviderRepositoryImpl.getDbContent(context, idOrNull, filePathOrNull); } @Override diff --git a/app/src/main/java/de/k3b/android/androFotoFinder/queries/MediaContentproviderRepositoryImpl.java b/app/src/main/java/de/k3b/android/androFotoFinder/queries/MediaContentproviderRepositoryImpl.java index b33158f3..5bc5c3f2 100644 --- a/app/src/main/java/de/k3b/android/androFotoFinder/queries/MediaContentproviderRepositoryImpl.java +++ b/app/src/main/java/de/k3b/android/androFotoFinder/queries/MediaContentproviderRepositoryImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2020 by k3b. + * Copyright (c) 2015-2021 by k3b. * * This file is part of AndroFotoFinder / #APhotoManager. * @@ -287,22 +287,36 @@ private static int _del_execRenameFolder_batch_not_working(Context context, Stri return ops.size(); } - public static ContentValues getDbContent(Context context, final long id) { - ContentResolver resolver = context.getContentResolver(); + public static ContentValues getDbContent(Context context, final Long idOrNull, String filePathOrNull) { + if (idOrNull != null || filePathOrNull != null) { + ContentResolver resolver = context.getContentResolver(); - Cursor c = null; - try { - c = resolver.query(FotoSqlBase.SQL_TABLE_EXTERNAL_CONTENT_URI_FILE, new String[]{"*"}, FotoSql.FILTER_COL_PK, new String[]{"" + id}, null); - if (c.moveToNext()) { - ContentValues values = new ContentValues(); - DatabaseUtils.cursorRowToContentValues(c, values); - return values; + Cursor c = null; + try { + String selection; + String[] selectionArgs; + if (filePathOrNull == null) { + selection = FotoSql.FILTER_COL_PK; + selectionArgs = new String[]{"" + idOrNull}; + } else if (idOrNull == null) { + selection = FotoSql.FILTER_EXPR_PATH_LIKE; + selectionArgs = new String[]{filePathOrNull}; + } else { + selection = FotoSql.FILTER_COL_PK + " or " + FotoSql.FILTER_EXPR_PATH_LIKE; + selectionArgs = new String[]{"" + idOrNull, filePathOrNull}; + } + c = resolver.query(FotoSqlBase.SQL_TABLE_EXTERNAL_CONTENT_URI_FILE, new String[]{"*"}, selection, selectionArgs, null); + if (c.moveToNext()) { + ContentValues values = new ContentValues(); + DatabaseUtils.cursorRowToContentValues(c, values); + return values; + } + } catch (Exception ex) { + Log.e(LOG_TAG, MODUL_NAME + + ".getDbContent(id=" + idOrNull + ", path='" + filePathOrNull + "') failed", ex); + } finally { + if (c != null) c.close(); } - } catch (Exception ex) { - Log.e(LOG_TAG, MODUL_NAME + - ".getDbContent(id=" + id + ") failed", ex); - } finally { - if (c != null) c.close(); } return null; } 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 77353bba..3845d958 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 @@ -207,21 +207,35 @@ public int exexUpdateImpl(String dbgContext, ContentValues values, String sqlWhe } @Override - public ContentValues getDbContent(long id) { - Cursor c = null; - try { - c = this.createCursorForQuery(null, "getDbContent", - Impl.DATABASE_TABLE_NAME, FotoSql.FILTER_COL_PK, new String[]{"" + id}, null, null, "*"); - if (c.moveToNext()) { - ContentValues values = new ContentValues(); - DatabaseUtils.cursorRowToContentValues(c, values); - return values; + public ContentValues getDbContent(Long idOrNull, String filePathOrNull) { + if (idOrNull != null || filePathOrNull != null) { + Cursor c = null; + try { + String selection; + String[] selectionArgs; + if (filePathOrNull == null) { + selection = FotoSql.FILTER_COL_PK; + selectionArgs = new String[]{"" + idOrNull}; + } else if (idOrNull == null) { + selection = FotoSql.FILTER_EXPR_PATH_LIKE; + selectionArgs = new String[]{filePathOrNull}; + } else { + selection = FotoSql.FILTER_COL_PK + " or " + FotoSql.FILTER_EXPR_PATH_LIKE; + selectionArgs = new String[]{"" + idOrNull, filePathOrNull}; + } + c = this.createCursorForQuery(null, "getDbContent", + Impl.DATABASE_TABLE_NAME, selection, selectionArgs, null, null, "*"); + if (c.moveToNext()) { + ContentValues values = new ContentValues(); + DatabaseUtils.cursorRowToContentValues(c, values); + return values; + } + } catch (Exception ex) { + Log.e(LOG_TAG, MODUL_NAME + + ".getDbContent(id=" + idOrNull + ", path='" + filePathOrNull + "') failed", ex); + } finally { + if (c != null) c.close(); } - } catch (Exception ex) { - Log.e(LOG_TAG, MODUL_NAME + - ".getDbContent(id=" + id + ") failed", ex); - } finally { - if (c != null) c.close(); } return null; } diff --git a/app/src/main/java/de/k3b/android/androFotoFinder/queries/MediaRepositoryApiWrapper.java b/app/src/main/java/de/k3b/android/androFotoFinder/queries/MediaRepositoryApiWrapper.java index 0530b615..72a7a882 100644 --- a/app/src/main/java/de/k3b/android/androFotoFinder/queries/MediaRepositoryApiWrapper.java +++ b/app/src/main/java/de/k3b/android/androFotoFinder/queries/MediaRepositoryApiWrapper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2020 by k3b. + * Copyright (c) 2019-2021 by k3b. * * This file is part of AndroFotoFinder / #APhotoManager. * @@ -40,7 +40,7 @@ public class MediaRepositoryApiWrapper implements IMediaRepositoryApi { /** * count the non path write calls */ - private int modifyCount = 0; + private final int modifyCount = 0; public MediaRepositoryApiWrapper(IMediaRepositoryApi child) { this(child, child, child); @@ -111,8 +111,8 @@ public int deleteMedia(String dbgContext, String where, String[] selectionArgs, } @Override - public ContentValues getDbContent(long id) { - return getReadChild().getDbContent(id); + public ContentValues getDbContent(Long idOrNull, String filePathOrNull) { + return this.getReadChild().getDbContent(idOrNull, filePathOrNull); } @Override diff --git a/app/src/main/java/de/k3b/android/androFotoFinder/queries/MergedMediaRepository.java b/app/src/main/java/de/k3b/android/androFotoFinder/queries/MergedMediaRepository.java index 693e5c52..3e4ab35b 100644 --- a/app/src/main/java/de/k3b/android/androFotoFinder/queries/MergedMediaRepository.java +++ b/app/src/main/java/de/k3b/android/androFotoFinder/queries/MergedMediaRepository.java @@ -204,4 +204,10 @@ public int deleteMedia(String dbgContext, String where, String[] selectionArgs, localDatabase.deleteMedia(dbgContext, where, selectionArgs, preventDeleteImageFile); return result; } + + @Override + public ContentValues getDbContent(Long idOrNull, String filePathOrNull) { + return this.contentProvider.getDbContent(idOrNull, filePathOrNull); + } + } diff --git a/app/src/main/java/de/k3b/android/io/AndroidFileFacade.java b/app/src/main/java/de/k3b/android/io/AndroidFileFacade.java index dc7bf339..c4144470 100644 --- a/app/src/main/java/de/k3b/android/io/AndroidFileFacade.java +++ b/app/src/main/java/de/k3b/android/io/AndroidFileFacade.java @@ -60,6 +60,15 @@ public class AndroidFileFacade extends FileFacade { */ private Uri readUri = null; + @Override + public String toString() { + String result = super.toString(); + if (readUri != null) { + result += "(" + readUri + ")"; + } + return result; + } + /** * false means do not try to load androidFile again */ diff --git a/app/src/main/java/de/k3b/android/util/ClipboardUtil.java b/app/src/main/java/de/k3b/android/util/ClipboardUtil.java index 2f20962c..61874de9 100644 --- a/app/src/main/java/de/k3b/android/util/ClipboardUtil.java +++ b/app/src/main/java/de/k3b/android/util/ClipboardUtil.java @@ -34,13 +34,15 @@ */ public class ClipboardUtil { - public static boolean addDirToClipboard(Context context, CharSequence dir) { + public static boolean addDirToClipboard(Context context, CharSequence dir, boolean withToast) { if (!StringUtils.isNullOrEmpty(dir)) { ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); if (clipboard != null) { ClipData clip = ClipData.newPlainText(context.getString(R.string.lbl_path), dir); clipboard.setPrimaryClip(clip); - Toast.makeText(context, dir, Toast.LENGTH_LONG).show(); + if (withToast) { + Toast.makeText(context, dir, Toast.LENGTH_LONG).show(); + } return true; } }