From b892b7b8d328d640d31bd87ffea888ff98e6d30f Mon Sep 17 00:00:00 2001 From: tzugen Date: Tue, 12 Oct 2021 16:19:33 +0200 Subject: [PATCH] Migrate PermissionUtil to Kotlin - Set min SDK to 16 (was 14), because READ_EXTERNAL_STORAGE is minimum 16 - Add new shortcut to Settings.kt class - Use showDialog util function --- dependencies.gradle | 2 +- .../ultrasonic/fragment/SettingsFragment.java | 6 +- .../moire/ultrasonic/util/PermissionUtil.java | 237 ---------------- .../ultrasonic/activity/NavigationActivity.kt | 11 +- .../ultrasonic/fragment/EditServerFragment.kt | 7 +- .../org/moire/ultrasonic/util/FileUtil.kt | 5 +- .../moire/ultrasonic/util/PermissionUtil.kt | 259 ++++++++++++++++++ .../org/moire/ultrasonic/util/Settings.kt | 17 ++ .../kotlin/org/moire/ultrasonic/util/Util.kt | 21 +- 9 files changed, 304 insertions(+), 261 deletions(-) delete mode 100644 ultrasonic/src/main/java/org/moire/ultrasonic/util/PermissionUtil.java create mode 100644 ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/PermissionUtil.kt diff --git a/dependencies.gradle b/dependencies.gradle index 70e160bb..0c1bf079 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -1,5 +1,5 @@ ext.versions = [ - minSdk : 14, + minSdk : 16, targetSdk : 29, compileSdk : 29, // You need to run ./gradlew wrapper after updating the version diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/SettingsFragment.java b/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/SettingsFragment.java index 3a7253d7..4be972db 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/SettingsFragment.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/SettingsFragment.java @@ -224,8 +224,7 @@ public class SettingsFragment extends PreferenceFragmentCompat } private void setupCacheLocationPreference() { - cacheLocation.setSummary(settings.getString(Constants.PREFERENCES_KEY_CACHE_LOCATION, - FileUtil.getDefaultMusicDirectory().getPath())); + cacheLocation.setSummary(Settings.getCacheLocation()); cacheLocation.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { @Override @@ -431,8 +430,7 @@ public class SettingsFragment extends PreferenceFragmentCompat sharingDefaultExpiration.setSummary(sharingDefaultExpiration.getText()); sharingDefaultDescription.setSummary(sharingDefaultDescription.getText()); sharingDefaultGreeting.setSummary(sharingDefaultGreeting.getText()); - cacheLocation.setSummary(settings.getString(Constants.PREFERENCES_KEY_CACHE_LOCATION, - FileUtil.getDefaultMusicDirectory().getPath())); + cacheLocation.setSummary(Settings.getCacheLocation()); if (!mediaButtonsEnabled.isChecked()) { lockScreenEnabled.setChecked(false); diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/util/PermissionUtil.java b/ultrasonic/src/main/java/org/moire/ultrasonic/util/PermissionUtil.java deleted file mode 100644 index cbf82fa7..00000000 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/util/PermissionUtil.java +++ /dev/null @@ -1,237 +0,0 @@ -package org.moire.ultrasonic.util; - -import android.Manifest; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.net.Uri; -import android.os.Handler; -import android.os.Looper; - -import androidx.annotation.Nullable; -import androidx.appcompat.app.AlertDialog; -import androidx.core.content.PermissionChecker; - -import com.karumi.dexter.Dexter; -import com.karumi.dexter.MultiplePermissionsReport; -import com.karumi.dexter.PermissionToken; -import com.karumi.dexter.listener.DexterError; -import com.karumi.dexter.listener.PermissionRequest; -import com.karumi.dexter.listener.PermissionRequestErrorListener; -import com.karumi.dexter.listener.multi.MultiplePermissionsListener; - -import org.moire.ultrasonic.R; - -import java.util.List; - -import timber.log.Timber; - -import static androidx.core.content.PermissionChecker.PERMISSION_DENIED; - - -/** - * Contains static functions for Permission handling - */ -public class PermissionUtil { - - private Context activityContext; - private final Context applicationContext; - - public PermissionUtil(Context context) { - applicationContext = context; - } - - public interface PermissionRequestFinishedCallback { - void onPermissionRequestFinished(boolean hasPermission); - } - - public void ForegroundApplicationStarted(Context context) { - this.activityContext = context; - } - - public void ForegroundApplicationStopped() { - activityContext = null; - } - - /** - * This function can be used to handle file access permission failures. - * - * It will check if the failure is because the necessary permissions aren't available, - * and it will request them, if necessary. - * - * @param callback callback function to execute after the permission request is finished - */ - public void handlePermissionFailed(@Nullable final PermissionRequestFinishedCallback callback) { - String currentCachePath = Settings.getPreferences().getString(Constants.PREFERENCES_KEY_CACHE_LOCATION, FileUtil.getDefaultMusicDirectory().getPath()); - String defaultCachePath = FileUtil.getDefaultMusicDirectory().getPath(); - - // Ultrasonic can do nothing about this error when the Music Directory is already set to the default. - if (currentCachePath.compareTo(defaultCachePath) == 0) return; - - if ((PermissionChecker.checkSelfPermission(applicationContext, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PERMISSION_DENIED) || - (PermissionChecker.checkSelfPermission(applicationContext, Manifest.permission.READ_EXTERNAL_STORAGE) == PERMISSION_DENIED)) { - // While we request permission, the Music Directory is temporarily reset to its default location - setCacheLocation(applicationContext, FileUtil.getDefaultMusicDirectory().getPath()); - // If the application is not running, we can't notify the user - if (activityContext == null) return; - requestFailedPermission(activityContext, currentCachePath, callback); - } else { - setCacheLocation(applicationContext, FileUtil.getDefaultMusicDirectory().getPath()); - // If the application is not running, we can't notify the user - if (activityContext != null) { - new Handler(Looper.getMainLooper()).post(new Runnable() { - @Override - public void run() { - showWarning(activityContext, activityContext.getString(R.string.permissions_message_box_title), activityContext.getString(R.string.permissions_access_error), null); - } - }); - } - if (callback != null) { - callback.onPermissionRequestFinished(false); - } - } - } - - /** - * This function requests permission to access the filesystem. - * It can be used to request the permission initially, e.g. when the user decides to use a non-default folder for the cache - * @param context context for the operation - * @param callback callback function to execute after the permission request is finished - */ - public static void requestInitialPermission(final Context context, final PermissionRequestFinishedCallback callback) { - Dexter.withContext(context) - .withPermissions( - Manifest.permission.WRITE_EXTERNAL_STORAGE, - Manifest.permission.READ_EXTERNAL_STORAGE) - .withListener(new MultiplePermissionsListener() { - @Override - public void onPermissionsChecked(MultiplePermissionsReport report) { - if (report.areAllPermissionsGranted()) { - Timber.i("Permission granted to read / write external storage"); - if (callback != null) callback.onPermissionRequestFinished(true); - return; - } - - if (report.isAnyPermissionPermanentlyDenied()) { - Timber.i("Found permanently denied permission to read / write external storage, offering settings"); - showSettingsDialog(context); - if (callback != null) callback.onPermissionRequestFinished(false); - return; - } - - Timber.i("At least one permission is missing to read / write external storage"); - showWarning(context, context.getString(R.string.permissions_message_box_title), - context.getString(R.string.permissions_rationale_description_initial), null); - if (callback != null) callback.onPermissionRequestFinished(false); - } - - @Override - public void onPermissionRationaleShouldBeShown(List permissions, PermissionToken token) { - showWarning(context, context.getString(R.string.permissions_rationale_title), - context.getString(R.string.permissions_rationale_description_initial), token); - } - }).withErrorListener(new PermissionRequestErrorListener() { - @Override - public void onError(DexterError error) { - Timber.e("An error has occurred during checking permissions with Dexter: %s", error.toString()); - } - }) - .check(); - } - - private static void setCacheLocation(Context context, String cacheLocation) { - Settings.getPreferences().edit() - .putString(Constants.PREFERENCES_KEY_CACHE_LOCATION, cacheLocation) - .apply(); - } - - private static void requestFailedPermission(final Context context, final String cacheLocation, final PermissionRequestFinishedCallback callback) { - Dexter.withContext(context) - .withPermissions( - Manifest.permission.WRITE_EXTERNAL_STORAGE, - Manifest.permission.READ_EXTERNAL_STORAGE) - .withListener(new MultiplePermissionsListener() { - @Override - public void onPermissionsChecked(MultiplePermissionsReport report) { - if (report.areAllPermissionsGranted()) { - Timber.i("Permission granted to use cache directory %s", cacheLocation); - setCacheLocation(context, cacheLocation); - if (callback != null) callback.onPermissionRequestFinished(true); - return; - } - - if (report.isAnyPermissionPermanentlyDenied()) { - Timber.i("Found permanently denied permission to use cache directory %s, offering settings", cacheLocation); - showSettingsDialog(context); - if (callback != null) callback.onPermissionRequestFinished(false); - return; - } - - Timber.i("At least one permission is missing to use directory %s ", cacheLocation); - setCacheLocation(context, FileUtil.getDefaultMusicDirectory().getPath()); - showWarning(context, context.getString(R.string.permissions_message_box_title), - context.getString(R.string.permissions_permission_missing), null); - if (callback != null) callback.onPermissionRequestFinished(false); - } - - @Override - public void onPermissionRationaleShouldBeShown(List permissions, PermissionToken token) { - showWarning(context, context.getString(R.string.permissions_rationale_title), - context.getString(R.string.permissions_rationale_description_failed), token); - } - }).withErrorListener(new PermissionRequestErrorListener() { - @Override - public void onError(DexterError error) { - Timber.e("An error has occurred during checking permissions with Dexter: %s", error.toString()); - } - }) - .check(); - } - - private static void showSettingsDialog(final Context context) { - AlertDialog.Builder builder = new AlertDialog.Builder(context, R.style.Theme_AppCompat_Dialog); - builder.setIcon(android.R.drawable.ic_dialog_alert); - builder.setTitle(context.getString(R.string.permissions_permanent_denial_title)); - builder.setMessage(context.getString(R.string.permissions_permanent_denial_description)); - - builder.setPositiveButton(context.getString(R.string.permissions_open_settings), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - dialog.cancel(); - openSettings(context); - } - }); - - builder.setNegativeButton(context.getString(R.string.common_cancel), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - setCacheLocation(context, FileUtil.getDefaultMusicDirectory().getPath()); - dialog.cancel(); - } - }); - - builder.show(); - } - - private static void openSettings(Context context) { - Intent i = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS); - i.addCategory(Intent.CATEGORY_DEFAULT); - i.setData(Uri.parse("package:" + context.getPackageName())); - context.startActivity(i); - } - - private static void showWarning(Context context, String title, String text, final PermissionToken token) { - AlertDialog.Builder builder = new AlertDialog.Builder(context, R.style.Theme_AppCompat_Dialog); - builder.setIcon(android.R.drawable.ic_dialog_alert); - builder.setTitle(title); - builder.setMessage(text); - builder.setPositiveButton(context.getString(R.string.common_ok), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - dialog.cancel(); - if (token != null) token.continuePermissionRequest(); - } - }); - builder.show(); - } -} diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/activity/NavigationActivity.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/activity/NavigationActivity.kt index f2e9a626..dc9ffe66 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/activity/NavigationActivity.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/activity/NavigationActivity.kt @@ -83,7 +83,7 @@ class NavigationActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { setUncaughtExceptionHandler() - permissionUtil.ForegroundApplicationStarted(this) + permissionUtil.onForegroundApplicationStarted(this) Util.applyTheme(this) super.onCreate(savedInstanceState) @@ -198,7 +198,7 @@ class NavigationActivity : AppCompatActivity() { nowPlayingEventDistributor.unsubscribe(nowPlayingEventListener) themeChangedEventDistributor.unsubscribe(themeChangedEventListener) imageLoaderProvider.clearImageLoader() - permissionUtil.ForegroundApplicationStopped() + permissionUtil.onForegroundApplicationStopped() } override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { @@ -304,12 +304,7 @@ class NavigationActivity : AppCompatActivity() { PreferenceManager.setDefaultValues(this, R.xml.settings, false) val preferences = Settings.preferences if (!preferences.contains(Constants.PREFERENCES_KEY_CACHE_LOCATION)) { - val editor = preferences.edit() - editor.putString( - Constants.PREFERENCES_KEY_CACHE_LOCATION, - FileUtil.defaultMusicDirectory.path - ) - editor.apply() + Settings.cacheLocation = FileUtil.defaultMusicDirectory.path } } diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/EditServerFragment.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/EditServerFragment.kt index 077a7587..57e75832 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/EditServerFragment.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/EditServerFragment.kt @@ -415,10 +415,9 @@ class EditServerFragment : Fragment(), OnBackPressedHandler { } Util.showDialog( - activity, - android.R.drawable.ic_dialog_info, - R.string.settings_testing_ok, - dialogText + context = requireActivity(), + titleId = R.string.settings_testing_ok, + message = dialogText ) } diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/FileUtil.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/FileUtil.kt index af5690e6..f9a03051 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/FileUtil.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/FileUtil.kt @@ -253,9 +253,8 @@ object FileUtil { @JvmStatic val musicDirectory: File get() { - val path = Settings.preferences - .getString(Constants.PREFERENCES_KEY_CACHE_LOCATION, defaultMusicDirectory.path) - val dir = File(path!!) + val path = Settings.cacheLocation + val dir = File(path) val hasAccess = ensureDirectoryExistsAndIsReadWritable(dir) if (!hasAccess) permissionUtil.value.handlePermissionFailed(null) return if (hasAccess) dir else defaultMusicDirectory diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/PermissionUtil.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/PermissionUtil.kt new file mode 100644 index 00000000..92813226 --- /dev/null +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/PermissionUtil.kt @@ -0,0 +1,259 @@ +package org.moire.ultrasonic.util + +import android.Manifest +import android.content.Context +import android.content.Intent +import android.net.Uri +import android.os.Handler +import android.os.Looper +import androidx.core.content.PermissionChecker +import com.karumi.dexter.Dexter +import com.karumi.dexter.MultiplePermissionsReport +import com.karumi.dexter.PermissionToken +import com.karumi.dexter.listener.PermissionRequest +import com.karumi.dexter.listener.multi.MultiplePermissionsListener +import org.moire.ultrasonic.R +import org.moire.ultrasonic.util.FileUtil.defaultMusicDirectory +import timber.log.Timber + +/** + * Contains static functions for Permission handling + */ +class PermissionUtil(private val applicationContext: Context) { + private var activityContext: Context? = null + + interface PermissionRequestFinishedCallback { + fun onPermissionRequestFinished(hasPermission: Boolean) + } + + fun onForegroundApplicationStarted(context: Context?) { + activityContext = context + } + + fun onForegroundApplicationStopped() { + activityContext = null + } + + /** + * This function can be used to handle file access permission failures. + * + * It will check if the failure is because the necessary permissions aren't available, + * and it will request them, if necessary. + * + * @param callback callback function to execute after the permission request is finished + */ + fun handlePermissionFailed(callback: PermissionRequestFinishedCallback?) { + val currentCachePath = Settings.cacheLocation + val defaultCachePath = defaultMusicDirectory.path + + // Ultrasonic can do nothing about this error when the Music Directory is already set to the default. + if (currentCachePath.compareTo(defaultCachePath) == 0) return + + if (PermissionChecker.checkSelfPermission( + applicationContext, + Manifest.permission.WRITE_EXTERNAL_STORAGE + ) == PermissionChecker.PERMISSION_DENIED || + PermissionChecker.checkSelfPermission( + applicationContext, + Manifest.permission.READ_EXTERNAL_STORAGE + ) == PermissionChecker.PERMISSION_DENIED + ) { + // While we request permission, the Music Directory is temporarily reset to its default location + Settings.cacheLocation = defaultMusicDirectory.path + // If the application is not running, we can't notify the user + if (activityContext == null) return + requestFailedPermission(activityContext!!, currentCachePath, callback) + } else { + Settings.cacheLocation = defaultMusicDirectory.path + // If the application is not running, we can't notify the user + if (activityContext != null) { + Handler(Looper.getMainLooper()).post { + showWarning( + activityContext!!, + activityContext!!.getString(R.string.permissions_message_box_title), + activityContext!!.getString(R.string.permissions_access_error), + null + ) + } + } + callback?.onPermissionRequestFinished(false) + } + } + + companion object { + /** + * This function requests permission to access the filesystem. + * It can be used to request the permission initially, e.g. when the user decides to + * use a non-default folder for the cache + * @param context context for the operation + * @param callback callback function to execute after the permission request is finished + */ + @JvmStatic + fun requestInitialPermission( + context: Context, + callback: PermissionRequestFinishedCallback? + ) { + Dexter.withContext(context) + .withPermissions( + Manifest.permission.WRITE_EXTERNAL_STORAGE, + Manifest.permission.READ_EXTERNAL_STORAGE + ) + .withListener(object : MultiplePermissionsListener { + override fun onPermissionsChecked(report: MultiplePermissionsReport) { + if (report.areAllPermissionsGranted()) { + Timber.i("R/W permission granted for external storage") + callback?.onPermissionRequestFinished(true) + return + } + if (report.isAnyPermissionPermanentlyDenied) { + Timber.i( + "R/W permission is permanently denied for external storage" + ) + showSettingsDialog(context) + callback?.onPermissionRequestFinished(false) + return + } + Timber.i("R/W permission is missing for external storage") + showWarning( + context, + context.getString(R.string.permissions_message_box_title), + context.getString(R.string.permissions_rationale_description_initial), + null + ) + callback?.onPermissionRequestFinished(false) + } + + override fun onPermissionRationaleShouldBeShown( + permissions: List, + token: PermissionToken + ) { + showWarning( + context, + context.getString(R.string.permissions_rationale_title), + context.getString(R.string.permissions_rationale_description_initial), + token + ) + } + }).withErrorListener { error -> + Timber.e( + "An error has occurred during checking permissions with Dexter: %s", + error.toString() + ) + } + .check() + } + + private fun requestFailedPermission( + context: Context, + cacheLocation: String?, + callback: PermissionRequestFinishedCallback? + ) { + Dexter.withContext(context) + .withPermissions( + Manifest.permission.WRITE_EXTERNAL_STORAGE, + Manifest.permission.READ_EXTERNAL_STORAGE + ) + .withListener(object : MultiplePermissionsListener { + override fun onPermissionsChecked(report: MultiplePermissionsReport) { + if (report.areAllPermissionsGranted()) { + Timber.i("Permission granted to use cache directory %s", cacheLocation) + + if (cacheLocation != null) { + Settings.cacheLocation = cacheLocation + } + callback?.onPermissionRequestFinished(true) + return + } + if (report.isAnyPermissionPermanentlyDenied) { + Timber.i( + "R/W permission for cache directory %s was permanently denied", + cacheLocation + ) + showSettingsDialog(context) + callback?.onPermissionRequestFinished(false) + return + } + Timber.i( + "At least one permission is missing to use directory %s ", + cacheLocation + ) + Settings.cacheLocation = defaultMusicDirectory.path + showWarning( + context, context.getString(R.string.permissions_message_box_title), + context.getString(R.string.permissions_permission_missing), null + ) + callback?.onPermissionRequestFinished(false) + } + + override fun onPermissionRationaleShouldBeShown( + permissions: List, + token: PermissionToken + ) { + showWarning( + context, + context.getString(R.string.permissions_rationale_title), + context.getString(R.string.permissions_rationale_description_failed), + token + ) + } + }).withErrorListener { error -> + Timber.e( + "An error has occurred during checking permissions with Dexter: %s", + error.toString() + ) + } + .check() + } + + private fun showSettingsDialog(ctx: Context) { + + val builder = Util.createDialog( + context = ctx, + android.R.drawable.ic_dialog_alert, + ctx.getString(R.string.permissions_permanent_denial_title), + ctx.getString(R.string.permissions_permanent_denial_description) + ) + + builder.setPositiveButton(ctx.getString(R.string.permissions_open_settings)) { + dialog, _ -> + dialog.cancel() + openSettings(ctx) + } + + builder.setNegativeButton(ctx.getString(R.string.common_cancel)) { dialog, _ -> + Settings.cacheLocation = defaultMusicDirectory.path + dialog.cancel() + } + + builder.show() + } + + private fun openSettings(context: Context) { + val i = Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS) + i.addCategory(Intent.CATEGORY_DEFAULT) + i.data = Uri.parse("package:" + context.packageName) + context.startActivity(i) + } + + private fun showWarning( + context: Context, + title: String, + text: String, + token: PermissionToken? + ) { + + val builder = Util.createDialog( + context = context, + android.R.drawable.ic_dialog_alert, + title, + text + ) + + builder.setPositiveButton(context.getString(R.string.common_ok)) { dialog, _ -> + dialog.cancel() + token?.continuePermissionRequest() + } + builder.show() + } + } +} diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/Settings.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/Settings.kt index ed8d2847..baf64f56 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/Settings.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/Settings.kt @@ -102,6 +102,23 @@ object Settings { return if (preloadCount == -1) Int.MAX_VALUE else preloadCount } + @JvmStatic + var cacheLocation: String + get() { + return preferences.getString( + Constants.PREFERENCES_KEY_CACHE_LOCATION, + FileUtil.defaultMusicDirectory.path + )!! + } + set(location) { + val editor = preferences.edit() + editor.putString( + Constants.PREFERENCES_KEY_CACHE_LOCATION, + location + ) + editor.apply() + } + @JvmStatic val cacheSizeMB: Int get() { diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/Util.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/Util.kt index 0336d393..3c5d2b91 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/Util.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/Util.kt @@ -393,17 +393,30 @@ object Util { // The AlertDialog requires an Activity context, app context is not enough // See https://stackoverflow.com/questions/5436822/ - fun showDialog(context: Context?, icon: Int, titleId: Int, message: String?) { - AlertDialog.Builder(context) + fun createDialog( + context: Context?, + icon: Int = android.R.drawable.ic_dialog_info, + title: String, + message: String? + ): AlertDialog.Builder { + return AlertDialog.Builder(context) .setIcon(icon) - .setTitle(titleId) + .setTitle(title) .setMessage(message) .setPositiveButton(R.string.common_ok) { dialog: DialogInterface, _: Int -> dialog.dismiss() } - .show() + } + + fun showDialog( + context: Context, + icon: Int = android.R.drawable.ic_dialog_info, + titleId: Int, + message: String? + ) { + createDialog(context, icon, context.getString(titleId, ""), message).show() } @JvmStatic