From d364401ea939a4fa960e99e0eff239ccbeb19e7e Mon Sep 17 00:00:00 2001 From: Erik Duisters Date: Sat, 2 Feb 2019 11:38:13 +0000 Subject: [PATCH] Use DialogFragment instead of an AlertDialog for runtime permissions --- src/org/kde/kdeconnect/Plugins/Plugin.java | 27 ++- .../UserInterface/AlertDialogFragment.java | 185 ++++++++++++++++++ .../UserInterface/DeviceFragment.java | 10 +- .../PermissionsAlertDialogFragment.java | 82 ++++++++ 4 files changed, 285 insertions(+), 19 deletions(-) create mode 100644 src/org/kde/kdeconnect/UserInterface/AlertDialogFragment.java create mode 100644 src/org/kde/kdeconnect/UserInterface/PermissionsAlertDialogFragment.java diff --git a/src/org/kde/kdeconnect/Plugins/Plugin.java b/src/org/kde/kdeconnect/Plugins/Plugin.java index b226426e..6a606cb1 100644 --- a/src/org/kde/kdeconnect/Plugins/Plugin.java +++ b/src/org/kde/kdeconnect/Plugins/Plugin.java @@ -29,12 +29,13 @@ import android.widget.Button; import org.kde.kdeconnect.Device; import org.kde.kdeconnect.NetworkPacket; +import org.kde.kdeconnect.UserInterface.AlertDialogFragment; +import org.kde.kdeconnect.UserInterface.PermissionsAlertDialogFragment; import org.kde.kdeconnect.UserInterface.PluginSettingsFragment; import org.kde.kdeconnect_tp.R; import androidx.annotation.StringRes; import androidx.appcompat.app.AlertDialog; -import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; public abstract class Plugin { @@ -223,18 +224,14 @@ public abstract class Plugin { return true; } - protected AlertDialog requestPermissionDialog(Activity activity, String permissions, @StringRes int reason) { - return requestPermissionDialog(activity, new String[]{permissions}, reason); - } - - private AlertDialog requestPermissionDialog(final Activity activity, final String[] permissions, @StringRes int reason) { - return new AlertDialog.Builder(activity) + private PermissionsAlertDialogFragment requestPermissionDialog(final String[] permissions, @StringRes int reason, int requestCode) { + return new PermissionsAlertDialogFragment.Builder() .setTitle(getDisplayName()) .setMessage(reason) - .setPositiveButton(R.string.ok, (dialogInterface, i) -> ActivityCompat.requestPermissions(activity, permissions, 0)) - .setNegativeButton(R.string.cancel, (dialogInterface, i) -> { - //Do nothing - }) + .setPositiveButton(R.string.ok) + .setNegativeButton(R.string.cancel) + .setPermissions(permissions) + .setRequestCode(requestCode) .create(); } @@ -247,12 +244,12 @@ public abstract class Plugin { return null; } - public AlertDialog getPermissionExplanationDialog(Activity deviceActivity) { - return requestPermissionDialog(deviceActivity, getRequiredPermissions(), permissionExplanation); + public AlertDialogFragment getPermissionExplanationDialog(int requestCode) { + return requestPermissionDialog(getRequiredPermissions(), permissionExplanation, requestCode); } - public AlertDialog getOptionalPermissionExplanationDialog(Activity deviceActivity) { - return requestPermissionDialog(deviceActivity, getOptionalPermissions(), optionalPermissionExplanation); + public AlertDialogFragment getOptionalPermissionExplanationDialog(int requestCode) { + return requestPermissionDialog(getOptionalPermissions(), optionalPermissionExplanation, requestCode); } public boolean checkRequiredPermissions() { diff --git a/src/org/kde/kdeconnect/UserInterface/AlertDialogFragment.java b/src/org/kde/kdeconnect/UserInterface/AlertDialogFragment.java new file mode 100644 index 00000000..cd92ddea --- /dev/null +++ b/src/org/kde/kdeconnect/UserInterface/AlertDialogFragment.java @@ -0,0 +1,185 @@ +/* + * Copyright 2019 Erik Duisters + * + * 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 2 of + * the License or (at your option) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * 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 org.kde.kdeconnect.UserInterface; + +import android.annotation.SuppressLint; +import android.app.Dialog; +import android.content.DialogInterface; +import android.os.Bundle; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.StringRes; +import androidx.appcompat.app.AlertDialog; +import androidx.fragment.app.DialogFragment; + +public class AlertDialogFragment extends DialogFragment implements DialogInterface.OnClickListener { + private static final String KEY_TITLE_RES_ID = "TitleResId"; + private static final String KEY_TITLE = "Title"; + private static final String KEY_MESSAGE_RES_ID = "MessageResId"; + private static final String KEY_POSITIVE_BUTTON_TEXT_RES_ID = "PositiveButtonResId"; + private static final String KEY_NEGATIVE_BUTTON_TEXT_RES_ID = "NegativeButtonResId"; + + @StringRes private int titleResId; + @Nullable private String title; + @StringRes private int messageResId; + @StringRes private int positiveButtonResId; + @StringRes private int negativeButtonResId; + + @Nullable private Callback callback; + + public AlertDialogFragment() { + } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + Bundle args = getArguments(); + + if (args == null) { + throw new RuntimeException("You need to instantiate a new AlertDialogFragment using AlertDialogFragment.Builder"); + } + + titleResId = args.getInt(KEY_TITLE_RES_ID); + title = args.getString(KEY_TITLE); + messageResId = args.getInt(KEY_MESSAGE_RES_ID); + positiveButtonResId = args.getInt(KEY_POSITIVE_BUTTON_TEXT_RES_ID); + negativeButtonResId = args.getInt(KEY_NEGATIVE_BUTTON_TEXT_RES_ID); + } + + @NonNull + @Override + public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { + @SuppressLint("ResourceType") + String titleString = titleResId > 0 ? getString(titleResId) : title; + + return new AlertDialog.Builder(requireContext()) + .setTitle(titleString) + .setMessage(messageResId) + .setPositiveButton(positiveButtonResId, this) + .setNegativeButton(negativeButtonResId, this) + .create(); + } + + public void setCallback(@Nullable Callback callback) { + this.callback = callback; + } + + @Override + public void onClick(DialogInterface dialog, int which) { + if (callback == null) { + return; + } + + switch (which) { + case AlertDialog.BUTTON_POSITIVE: + callback.onPositiveButtonClicked(); + break; + case AlertDialog.BUTTON_NEGATIVE: + callback.onNegativeButtonClicked(); + break; + default: + break; + } + } + + @Override + public void onCancel(DialogInterface dialog) { + super.onCancel(dialog); + + if (callback != null) { + callback.onCancel(); + } + } + + @Override + public void onDismiss(DialogInterface dialog) { + super.onDismiss(dialog); + + if (callback != null) { + callback.onDismiss(); + } + } + + public static abstract class AbstractBuilder, F extends DialogFragment> { + Bundle args; + + AbstractBuilder() { + args = new Bundle(); + } + + public abstract B getThis(); + + public B setTitle(@StringRes int titleResId) { + args.putInt(KEY_TITLE_RES_ID, titleResId); + return getThis(); + } + + public B setTitle(@NonNull String title) { + args.putString(KEY_TITLE, title); + return getThis(); + } + + public B setMessage(@StringRes int messageResId) { + args.putInt(KEY_MESSAGE_RES_ID, messageResId); + return getThis(); + } + + public B setPositiveButton(@StringRes int positiveButtonResId) { + args.putInt(KEY_POSITIVE_BUTTON_TEXT_RES_ID, positiveButtonResId); + return getThis(); + } + + public B setNegativeButton(@StringRes int negativeButtonResId) { + args.putInt(KEY_NEGATIVE_BUTTON_TEXT_RES_ID, negativeButtonResId); + return getThis(); + } + + protected abstract F createFragment(); + + public F create() { + F fragment = createFragment(); + fragment.setArguments(args); + + return fragment; + } + } + + public static class Builder extends AbstractBuilder { + @Override + public Builder getThis() { + return this; + } + + @Override + protected AlertDialogFragment createFragment() { + return new AlertDialogFragment(); + } + } + + public static abstract class Callback { + public void onPositiveButtonClicked() {} + public void onNegativeButtonClicked() {} + public void onDismiss() {} + public void onCancel() {} + } +} diff --git a/src/org/kde/kdeconnect/UserInterface/DeviceFragment.java b/src/org/kde/kdeconnect/UserInterface/DeviceFragment.java index e6262a3f..24cb3ab4 100644 --- a/src/org/kde/kdeconnect/UserInterface/DeviceFragment.java +++ b/src/org/kde/kdeconnect/UserInterface/DeviceFragment.java @@ -338,15 +338,17 @@ public class DeviceFragment extends Fragment { } }); DeviceFragment.this.createPluginsList(device.getPluginsWithoutPermissions(), R.string.plugins_need_permission, (plugin) -> { - AlertDialog dialog = plugin.getPermissionExplanationDialog(mActivity); + AlertDialogFragment dialog = plugin.getPermissionExplanationDialog(0); + if (dialog != null) { - dialog.show(); + dialog.show(getChildFragmentManager(), null); } }); DeviceFragment.this.createPluginsList(device.getPluginsWithoutOptionalPermissions(), R.string.plugins_need_optional_permission, (plugin) -> { - AlertDialog dialog = plugin.getOptionalPermissionExplanationDialog(mActivity); + AlertDialogFragment dialog = plugin.getOptionalPermissionExplanationDialog(0); + if (dialog != null) { - dialog.show(); + dialog.show(getChildFragmentManager(), null); } }); } diff --git a/src/org/kde/kdeconnect/UserInterface/PermissionsAlertDialogFragment.java b/src/org/kde/kdeconnect/UserInterface/PermissionsAlertDialogFragment.java new file mode 100644 index 00000000..7341b095 --- /dev/null +++ b/src/org/kde/kdeconnect/UserInterface/PermissionsAlertDialogFragment.java @@ -0,0 +1,82 @@ +/* + * Copyright 2019 Erik Duisters + * + * 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 2 of + * the License or (at your option) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * 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 org.kde.kdeconnect.UserInterface; + +import android.os.Bundle; + +import androidx.annotation.Nullable; +import androidx.core.app.ActivityCompat; + +public class PermissionsAlertDialogFragment extends AlertDialogFragment { + private static final String KEY_PERMISSIONS = "Permissions"; + private static final String KEY_REQUEST_CODE = "RequestCode"; + + private String[] permissions; + private int requestCode; + + public PermissionsAlertDialogFragment() { + } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + Bundle args = getArguments(); + + if (args == null || !args.containsKey(KEY_PERMISSIONS)) { + throw new RuntimeException("You must call Builder.setPermission() to set the array of needed permissions"); + } + + permissions = args.getStringArray(KEY_PERMISSIONS); + requestCode = args.getInt(KEY_REQUEST_CODE, 0); + + setCallback(new Callback() { + @Override + public void onPositiveButtonClicked() { + ActivityCompat.requestPermissions(requireActivity(), permissions, requestCode); + } + }); + } + + public static class Builder extends AlertDialogFragment.AbstractBuilder { + @Override + public Builder getThis() { + return this; + } + + public Builder setPermissions(String[] permissions) { + args.putStringArray(KEY_PERMISSIONS, permissions); + + return getThis(); + } + + public Builder setRequestCode(int requestCode) { + args.putInt(KEY_REQUEST_CODE, requestCode); + + return getThis(); + } + + @Override + protected PermissionsAlertDialogFragment createFragment() { + return new PermissionsAlertDialogFragment(); + } + } +}