diff --git a/app/src/main/java/de/k3b/android/androFotoFinder/BaseActivity.java b/app/src/main/java/de/k3b/android/androFotoFinder/BaseActivity.java new file mode 100644 index 00000000..b995d08b --- /dev/null +++ b/app/src/main/java/de/k3b/android/androFotoFinder/BaseActivity.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2020 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 + */ + +package de.k3b.android.androFotoFinder; + +import de.k3b.android.widget.ActivityWithAutoCloseDialogs; +import de.k3b.android.widget.ActivityWithCallContext; +import de.k3b.android.widget.BaseQueryActivity; +import de.k3b.android.widget.FilePermissionActivity; +import de.k3b.android.widget.LocalizedActivity; +import de.k3b.android.widget.PermissionBaseActivity; + +/** + * Nearly all activities are inherited from {@link BaseActivity}. + * * {@link FilePermissionActivity} manage permission write to external-storage and to sdcard + * * {@link PermissionBaseActivity} can Ask for permission + * * {@link ActivityWithAutoCloseDialogs} Automatically closes pop-dialogs + * * {@link LocalizedActivity} Change the locale (language) and translation of its content at runtime + * * {@link ActivityWithCallContext} memorizes the activity call stack (parent Activities) for debugging purposes. + *

+ * * {@link BaseQueryActivity} filtered collection of photos used by + * ** {@link de.k3b.android.androFotoFinder.FotoGalleryActivity} + * ** {@link de.k3b.android.androFotoFinder.locationmap.MapGeoPickerActivity} + */ +public abstract class BaseActivity extends FilePermissionActivity { +} diff --git a/app/src/main/java/de/k3b/android/androFotoFinder/GalleryFilterActivity.java b/app/src/main/java/de/k3b/android/androFotoFinder/GalleryFilterActivity.java index 95860fa8..2c25ec92 100644 --- a/app/src/main/java/de/k3b/android/androFotoFinder/GalleryFilterActivity.java +++ b/app/src/main/java/de/k3b/android/androFotoFinder/GalleryFilterActivity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2019 by k3b. + * Copyright (c) 2015-2020 by k3b. * * This file is part of AndroFotoFinder / #APhotoManager. * @@ -60,7 +60,6 @@ import de.k3b.android.osmdroid.OsmdroidUtil; import de.k3b.android.util.IntentUtil; import de.k3b.android.widget.AboutDialogPreference; -import de.k3b.android.widget.ActivityWithAutoCloseDialogs; import de.k3b.android.widget.BaseQueryActivity; import de.k3b.android.widget.HistoryEditText; import de.k3b.database.QueryParameter; @@ -79,7 +78,7 @@ * * Defines a gui for global foto filter: only fotos from certain filepath, date and/or lat/lon will be visible. */ -public class GalleryFilterActivity extends ActivityWithAutoCloseDialogs +public class GalleryFilterActivity extends BaseActivity implements Common, DirectoryPickerFragment.OnDirectoryInteractionListener, LocationMapFragment.OnDirectoryInteractionListener, TagsPickerFragment.ITagsPicker 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 879c3d94..71a5fa8a 100644 --- a/app/src/main/java/de/k3b/android/androFotoFinder/PhotoAutoprocessingEditActivity.java +++ b/app/src/main/java/de/k3b/android/androFotoFinder/PhotoAutoprocessingEditActivity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 by k3b. + * Copyright (c) 2017-2020 by k3b. * * This file is part of AndroFotoFinder / #APhotoManager. * @@ -58,7 +58,6 @@ import de.k3b.android.util.ClipboardUtil; import de.k3b.android.util.IntentUtil; import de.k3b.android.widget.AboutDialogPreference; -import de.k3b.android.widget.ActivityWithAutoCloseDialogs; import de.k3b.android.widget.HistoryEditText; import de.k3b.io.DateUtil; import de.k3b.io.ListUtils; @@ -78,7 +77,7 @@ * * filename schemata for copied/moved files * * default properties that every photot should receive. */ -public class PhotoAutoprocessingEditActivity extends ActivityWithAutoCloseDialogs implements Common { +public class PhotoAutoprocessingEditActivity extends BaseActivity implements Common { private static final String mDebugPrefix = "AutoProcEdit-"; private static final String SETTINGS_KEY = "AutoProcEditCurrent-"; private static final int EXIF_EDIT_RESULT_ID = 86441; diff --git a/app/src/main/java/de/k3b/android/androFotoFinder/PhotoPropertiesEditActivity.java b/app/src/main/java/de/k3b/android/androFotoFinder/PhotoPropertiesEditActivity.java index e862c303..230e1751 100644 --- a/app/src/main/java/de/k3b/android/androFotoFinder/PhotoPropertiesEditActivity.java +++ b/app/src/main/java/de/k3b/android/androFotoFinder/PhotoPropertiesEditActivity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 by k3b. + * Copyright (c) 2017-2020 by k3b. * * This file is part of AndroFotoFinder / #APhotoManager. * @@ -61,7 +61,6 @@ import de.k3b.android.util.PhotoPropertiesMediaFilesScanner; import de.k3b.android.util.ResourceUtils; import de.k3b.android.widget.AboutDialogPreference; -import de.k3b.android.widget.ActivityWithAutoCloseDialogs; import de.k3b.android.widget.HistoryEditText; import de.k3b.android.widget.UpdateTask; import de.k3b.geo.api.GeoPointDto; @@ -86,7 +85,7 @@ * Modes: if IPhotoProperties is not null edit exif data witout modifying any jpg file. * Modes: else if data-url/SelectedFiles is not null: modify the referenced jpg files. */ -public class PhotoPropertiesEditActivity extends ActivityWithAutoCloseDialogs implements Common { +public class PhotoPropertiesEditActivity extends BaseActivity implements Common { private static final boolean SYNC_UPDATE_EXIF = false; // for sync debugging. false: asynch task private static final String mDebugPrefix = "ExifEdit-"; private static final String DLG_NAVIGATOR_TAG = mDebugPrefix; @@ -380,7 +379,7 @@ public boolean onOptionsItemSelected(MenuItem item) { finish(); return true; case R.id.cmd_ok: - onOk(); + onSaveChanges(); return true; case R.id.cmd_clear: clearFilter(); @@ -796,7 +795,7 @@ private void clearFilter() { } /** save exif changes back to image and database */ - private void onOk() { + private void onSaveChanges() { Activity ctx = this; saveGuiToExif("onOk (finish)"); mHistory.saveHistory(); diff --git a/app/src/main/java/de/k3b/android/androFotoFinder/backup/BackupActivity.java b/app/src/main/java/de/k3b/android/androFotoFinder/backup/BackupActivity.java index b76a7303..0bf0625c 100644 --- a/app/src/main/java/de/k3b/android/androFotoFinder/backup/BackupActivity.java +++ b/app/src/main/java/de/k3b/android/androFotoFinder/backup/BackupActivity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2019 by k3b. + * Copyright (c) 2018-2020 by k3b. * * This file is part of AndroFotoFinder / #APhotoManager. * @@ -52,6 +52,7 @@ import java.util.TimeZone; import de.k3b.android.androFotoFinder.AffUtils; +import de.k3b.android.androFotoFinder.BaseActivity; import de.k3b.android.androFotoFinder.Common; import de.k3b.android.androFotoFinder.FotoGalleryActivity; import de.k3b.android.androFotoFinder.GalleryFilterActivity; @@ -68,7 +69,6 @@ import de.k3b.android.util.IntentUtil; import de.k3b.android.util.OsUtils; import de.k3b.android.widget.AboutDialogPreference; -import de.k3b.android.widget.ActivityWithAutoCloseDialogs; import de.k3b.android.widget.HistoryEditText; import de.k3b.database.QueryParameter; import de.k3b.io.DateUtil; @@ -95,7 +95,7 @@ * * uri = intent.getData() load file via file-uri * * else intent.Extra[EXTRA_STATE_ZIP_CONFIG] */ -public class BackupActivity extends ActivityWithAutoCloseDialogs implements Common { +public class BackupActivity extends BaseActivity implements Common { private static final int REQUEST_ID_PICK_ZIP_OUT_DIR = 1234; public static final int REQUEST_BACKUP_ID = 99289; diff --git a/app/src/main/java/de/k3b/android/androFotoFinder/imagedetail/ImageDetailActivityViewPager.java b/app/src/main/java/de/k3b/android/androFotoFinder/imagedetail/ImageDetailActivityViewPager.java index 51fcbd8c..8f244943 100644 --- a/app/src/main/java/de/k3b/android/androFotoFinder/imagedetail/ImageDetailActivityViewPager.java +++ b/app/src/main/java/de/k3b/android/androFotoFinder/imagedetail/ImageDetailActivityViewPager.java @@ -49,6 +49,7 @@ import java.util.List; import de.k3b.android.androFotoFinder.AffUtils; +import de.k3b.android.androFotoFinder.BaseActivity; import de.k3b.android.androFotoFinder.Common; import de.k3b.android.androFotoFinder.FotoGalleryActivity; import de.k3b.android.androFotoFinder.Global; @@ -71,7 +72,6 @@ import de.k3b.android.util.PhotoPropertiesMediaFilesScanner; import de.k3b.android.util.PhotoPropertiesMediaFilesScannerAsyncTask; import de.k3b.android.widget.AboutDialogPreference; -import de.k3b.android.widget.ActivityWithAutoCloseDialogs; import de.k3b.android.widget.ActivityWithCallContext; import de.k3b.android.widget.Dialogs; import de.k3b.database.QueryParameter; @@ -93,7 +93,7 @@ * Swipe left/right to show previous/next image. */ -public class ImageDetailActivityViewPager extends ActivityWithAutoCloseDialogs implements Common, TagsPickerFragment.ITagsPicker, +public class ImageDetailActivityViewPager extends BaseActivity implements Common, TagsPickerFragment.ITagsPicker, PhotoChangeNotifyer.PhotoChangedListener { private static final String INSTANCE_STATE_MODIFY_COUNT = "mModifyCount"; private static final String INSTANCE_STATE_LAST_SCROLL_POSITION = "lastScrollPosition"; @@ -1283,7 +1283,7 @@ public SelectedFiles getSrcFotos() { } /** - * To be overwritten to check if a path can be picked. + * To be overwritten to check if a path can be picked for writing. * * @param path to be checked if it cannot be handled * @return null if no error else error message with the reason why it cannot be selected diff --git a/app/src/main/java/de/k3b/android/widget/ActivityWithAutoCloseDialogs.java b/app/src/main/java/de/k3b/android/widget/ActivityWithAutoCloseDialogs.java index 98a89db4..0124da27 100644 --- a/app/src/main/java/de/k3b/android/widget/ActivityWithAutoCloseDialogs.java +++ b/app/src/main/java/de/k3b/android/widget/ActivityWithAutoCloseDialogs.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 by k3b. + * Copyright (c) 2017-2020 by k3b. * * This file is part of AndroFotoFinder / #APhotoManager. * @@ -36,7 +36,7 @@ * Created by k3b on 21.06.2017. */ -public class ActivityWithAutoCloseDialogs extends LocalizedActivity { +public abstract class ActivityWithAutoCloseDialogs extends LocalizedActivity { protected DialogFragment mCurrentDialogFragment; private Closeable mCloseable; private DialogInterface mCurrentDialog; diff --git a/app/src/main/java/de/k3b/android/widget/ActivityWithCallContext.java b/app/src/main/java/de/k3b/android/widget/ActivityWithCallContext.java index e27dcb58..51f325fd 100644 --- a/app/src/main/java/de/k3b/android/widget/ActivityWithCallContext.java +++ b/app/src/main/java/de/k3b/android/widget/ActivityWithCallContext.java @@ -31,7 +31,7 @@ *

* Created by k3b on 25.08.2018. */ -public class ActivityWithCallContext extends Activity { +public abstract class ActivityWithCallContext extends Activity { /** * the CallContext is an intent-extra with this name */ diff --git a/app/src/main/java/de/k3b/android/widget/BaseQueryActivity.java b/app/src/main/java/de/k3b/android/widget/BaseQueryActivity.java index e9e17774..8d55a66a 100644 --- a/app/src/main/java/de/k3b/android/widget/BaseQueryActivity.java +++ b/app/src/main/java/de/k3b/android/widget/BaseQueryActivity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2019 by k3b. + * Copyright (c) 2015-2020 by k3b. * * This file is part of AndroFotoFinder / #APhotoManager. * @@ -41,6 +41,7 @@ import java.util.List; import de.k3b.LibGlobal; +import de.k3b.android.androFotoFinder.BaseActivity; import de.k3b.android.androFotoFinder.Common; import de.k3b.android.androFotoFinder.GalleryFilterActivity; import de.k3b.android.androFotoFinder.GalleryFilterPathState; @@ -70,11 +71,12 @@ import de.k3b.tagDB.Tag; /** - * All that is is needed for to have a base-filter plus a sub-filter + * An activity that can have a filtered collection of photos based on + * a base-filter plus a sub-filter * * Created by k3b on 10.07.2018. */ -public abstract class BaseQueryActivity extends ActivityWithAutoCloseDialogs implements Common, DirectoryPickerFragment.OnDirectoryInteractionListener, +public abstract class BaseQueryActivity extends BaseActivity implements Common, DirectoryPickerFragment.OnDirectoryInteractionListener, LocationMapFragment.OnDirectoryInteractionListener, TagsPickerFragment.ITagsPicker { protected static final String mDebugPrefix = "GalleryA-"; diff --git a/app/src/main/java/de/k3b/android/widget/FilePermissionActivity.java b/app/src/main/java/de/k3b/android/widget/FilePermissionActivity.java new file mode 100644 index 00000000..1f7b5304 --- /dev/null +++ b/app/src/main/java/de/k3b/android/widget/FilePermissionActivity.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2020 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 + */ + +package de.k3b.android.widget; + +import android.Manifest; + +/** + * Manage permission + * * write to external-storage and + * * write to sdcard/usbstick,.... + */ +public abstract class FilePermissionActivity extends PermissionBaseActivity { + private void t() { + super.requestPermisson(Manifest.permission.WRITE_EXTERNAL_STORAGE, + "To %s the app needs write permission.", + (_this, result) -> onSaveChangesWithGrant(_this, result)); + + } +} diff --git a/app/src/main/java/de/k3b/android/widget/LocalizedActivity.java b/app/src/main/java/de/k3b/android/widget/LocalizedActivity.java index 0df6a22d..9d5aa423 100644 --- a/app/src/main/java/de/k3b/android/widget/LocalizedActivity.java +++ b/app/src/main/java/de/k3b/android/widget/LocalizedActivity.java @@ -35,7 +35,7 @@ import de.k3b.android.util.UserTheme; /** - * An activity that can change the locale (language) of its content. + * An activity that can change the locale (language) and translation of its content at runtime. * * Inspired by http://stackoverflow.com/questions/13181847/change-the-locale-at-runtime * diff --git a/app/src/main/java/de/k3b/android/widget/PermissionBaseActivity.java b/app/src/main/java/de/k3b/android/widget/PermissionBaseActivity.java new file mode 100644 index 00000000..09232b3e --- /dev/null +++ b/app/src/main/java/de/k3b/android/widget/PermissionBaseActivity.java @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2020 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 + */ + +package de.k3b.android.widget; + +import android.app.Activity; +import android.content.pm.PackageManager; +import android.os.Build; +import android.support.v4.app.ActivityCompat; + +import java.util.HashMap; +import java.util.Map; + +/** + * can Ask for permission + *

+ * inspired by Oleksii Shliama (https://github.com/shliama). + *

+ * Workflow + * saveAsPublicCroppedImage() { + * requestPermission(REQUEST_SAVE_EDIT_PICTURE_PERMISSION) + *

+ * onRequestPermissionsResult(REQUEST_SAVE_EDIT_PICTURE_PERMISSION) + * openPublicOutputUriPicker: + * startActivityForResult(new Intent(Intent.ACTION_CREATE_DOCUMENT), REQUEST_SAVE_EDIT_PICTURE_AS); + *

+ * onActivityResult(REQUEST_SAVE_EDIT_PICTURE_AS, RESULT_OK, data) : + * edit.onSaveEditPictureAsOutputUriPickerResult(outUri=data.getData()) + */ +public abstract class PermissionBaseActivity extends ActivityWithAutoCloseDialogs { + private static final CallbackHandler permissionHandler = new CallbackHandler(); + + /** + * @param permission i.e. Manifest.permission.READ_EXTERNAL_STORAGE + * @param resultHanlder + */ + protected void requestPermission(final String permission, CallbackHandler.IPermissionResult resultHanlder) { + Integer id = permissionHandler.getOrCreateId(resultHanlder); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN + && ActivityCompat.checkSelfPermission(this, permission) + != PackageManager.PERMISSION_GRANTED) { + requestPermission(permission, id); + } else { + resultHanlder.onPermissionResult(this, true, null); + } + } + + /** + * Requests given permission. + * If the permission has been denied previously, a Dialog will prompt the user to grant the + * permission, otherwise it is requested directly. + */ + private void requestPermission(final String permission, final int requestCode) { + ActivityCompat.requestPermissions(this, new String[]{permission}, requestCode); + } + + /** + * Callback received when a permissions request has been completed. + */ + @Override + public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { + final boolean success = grantResults[0] == PackageManager.PERMISSION_GRANTED; + CallbackHandler.IPermissionResult callback = permissionHandler.id2Callback(Integer.valueOf(requestCode)); + if (callback != null) { + permissionHandler.id2Callback.put(requestCode, null); + permissionHandler.callback2Id.put(callback, null); + callback.onPermissionResult(this, success, null); + } else { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + } + } + + private static class CallbackHandler { + private static Integer nextId = 1000; + ; + private final Map id2Callback = new HashMap<>(); + private final Map callback2Id = new HashMap<>(); + + public Integer getOrCreateId(IPermissionResult resultHanlder) { + Integer id = callback2Id.get(resultHanlder); + if (id == null) { + id = nextId++; + callback2Id.put(resultHanlder, id); + id2Callback.put(id, resultHanlder); + } + return id; + } + + public IPermissionResult id2Callback(Integer requestId) { + return id2Callback(requestId); + } + + protected interface IPermissionResult { + boolean onPermissionResult(THIS activity, boolean success, RESULT_DATA resultData); + } + } + +} diff --git a/fastlane/metadata/android/en-US/changelogs/48.txt b/fastlane/metadata/android/en-US/changelogs/48.txt new file mode 100644 index 00000000..1fbc7405 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/48.txt @@ -0,0 +1,5 @@ +Changes from 0.8.3 to ??? + +* ? #169: Add sd-card-saf-write-permission support +* ? translation updates +* APhotoManager is not Android-10 (api-29) ready yet.