From df9ceb0f101ec5696b5e4fd660791a4876205680 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jc=20Mi=C3=B1arro?= Date: Mon, 8 Jun 2020 09:13:17 +0200 Subject: [PATCH] Snackbar on permanently denied permission Listener (#260) * Extract Listener behavior * Extract show Snackbar behavior * Create SnackbarOnPermanentlyDeniedPermissionListener * Create SnackbarOnAnyPermanentlyDeniedMultiplePermissionsListener --- .../listener/SettingsClickListener.java | 19 +++ .../karumi/dexter/listener/SnackbarUtils.java | 22 +++ ...nAnyDeniedMultiplePermissionsListener.java | 36 +---- ...ntlyDeniedMultiplePermissionsListener.java | 146 +++++++++++++++++ .../SnackbarOnDeniedPermissionListener.java | 33 +--- ...OnPermanentlyDeniedPermissionListener.java | 147 ++++++++++++++++++ 6 files changed, 350 insertions(+), 53 deletions(-) create mode 100644 dexter/src/main/java/com/karumi/dexter/listener/SettingsClickListener.java create mode 100644 dexter/src/main/java/com/karumi/dexter/listener/SnackbarUtils.java create mode 100644 dexter/src/main/java/com/karumi/dexter/listener/multi/SnackbarOnAnyPermanentlyDeniedMultiplePermissionsListener.java create mode 100644 dexter/src/main/java/com/karumi/dexter/listener/single/SnackbarOnPermanentlyDeniedPermissionListener.java diff --git a/dexter/src/main/java/com/karumi/dexter/listener/SettingsClickListener.java b/dexter/src/main/java/com/karumi/dexter/listener/SettingsClickListener.java new file mode 100644 index 00000000..9363d4f1 --- /dev/null +++ b/dexter/src/main/java/com/karumi/dexter/listener/SettingsClickListener.java @@ -0,0 +1,19 @@ +package com.karumi.dexter.listener; + +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.provider.Settings; +import android.view.View; + +public class SettingsClickListener implements View.OnClickListener { + @Override + public void onClick(View view) { + Context context = view.getContext(); + Intent myAppSettings = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, + Uri.parse("package:" + context.getPackageName())); + myAppSettings.addCategory(Intent.CATEGORY_DEFAULT); + myAppSettings.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(myAppSettings); + } +} diff --git a/dexter/src/main/java/com/karumi/dexter/listener/SnackbarUtils.java b/dexter/src/main/java/com/karumi/dexter/listener/SnackbarUtils.java new file mode 100644 index 00000000..edc4bb24 --- /dev/null +++ b/dexter/src/main/java/com/karumi/dexter/listener/SnackbarUtils.java @@ -0,0 +1,22 @@ +package com.karumi.dexter.listener; + +import android.view.View; + +import com.google.android.material.snackbar.BaseTransientBottomBar; +import com.google.android.material.snackbar.Snackbar; + +public class SnackbarUtils { + + public static void show(View view, String text, int duration, String buttonText, + View.OnClickListener onButtonClickListener, + BaseTransientBottomBar.BaseCallback snackbarCallback) { + Snackbar snackbar = Snackbar.make(view, text, duration); + if (buttonText != null && onButtonClickListener != null) { + snackbar.setAction(buttonText, onButtonClickListener); + } + if (snackbarCallback != null) { + snackbar.addCallback(snackbarCallback); + } + snackbar.show(); + } +} diff --git a/dexter/src/main/java/com/karumi/dexter/listener/multi/SnackbarOnAnyDeniedMultiplePermissionsListener.java b/dexter/src/main/java/com/karumi/dexter/listener/multi/SnackbarOnAnyDeniedMultiplePermissionsListener.java index 8a0035e2..7c892b8b 100644 --- a/dexter/src/main/java/com/karumi/dexter/listener/multi/SnackbarOnAnyDeniedMultiplePermissionsListener.java +++ b/dexter/src/main/java/com/karumi/dexter/listener/multi/SnackbarOnAnyDeniedMultiplePermissionsListener.java @@ -16,14 +16,14 @@ package com.karumi.dexter.listener.multi; -import android.content.Context; -import android.content.Intent; -import android.net.Uri; -import android.provider.Settings; -import androidx.annotation.StringRes; -import com.google.android.material.snackbar.Snackbar; import android.view.View; + +import com.google.android.material.snackbar.Snackbar; import com.karumi.dexter.MultiplePermissionsReport; +import com.karumi.dexter.listener.SettingsClickListener; +import com.karumi.dexter.listener.SnackbarUtils; + +import androidx.annotation.StringRes; /** * Utility listener that shows a {@link Snackbar} with a custom text whenever a permission has been @@ -60,19 +60,8 @@ private SnackbarOnAnyDeniedMultiplePermissionsListener(View view, String text, super.onPermissionsChecked(report); if (!report.areAllPermissionsGranted()) { - showSnackbar(); - } - } - - private void showSnackbar() { - Snackbar snackbar = Snackbar.make(view, text, duration); - if (buttonText != null && onButtonClickListener != null) { - snackbar.setAction(buttonText, onButtonClickListener); - } - if (snackbarCallback != null) { - snackbar.addCallback(snackbarCallback); + SnackbarUtils.show(view, text, duration, buttonText, onButtonClickListener, snackbarCallback); } - snackbar.show(); } /** @@ -122,16 +111,7 @@ public Builder withButton(@StringRes int buttonTextResourceId, */ public Builder withOpenSettingsButton(String buttonText) { this.buttonText = buttonText; - this.onClickListener = new View.OnClickListener() { - @Override public void onClick(View v) { - Context context = view.getContext(); - Intent myAppSettings = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, - Uri.parse("package:" + context.getPackageName())); - myAppSettings.addCategory(Intent.CATEGORY_DEFAULT); - myAppSettings.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - context.startActivity(myAppSettings); - } - }; + this.onClickListener = new SettingsClickListener(); return this; } diff --git a/dexter/src/main/java/com/karumi/dexter/listener/multi/SnackbarOnAnyPermanentlyDeniedMultiplePermissionsListener.java b/dexter/src/main/java/com/karumi/dexter/listener/multi/SnackbarOnAnyPermanentlyDeniedMultiplePermissionsListener.java new file mode 100644 index 00000000..77d9ebf6 --- /dev/null +++ b/dexter/src/main/java/com/karumi/dexter/listener/multi/SnackbarOnAnyPermanentlyDeniedMultiplePermissionsListener.java @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2015 Karumi. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.karumi.dexter.listener.multi; + +import android.view.View; + +import com.google.android.material.snackbar.Snackbar; +import com.karumi.dexter.MultiplePermissionsReport; +import com.karumi.dexter.listener.SettingsClickListener; +import com.karumi.dexter.listener.SnackbarUtils; + +import androidx.annotation.StringRes; + +/** + * Utility listener that shows a {@link Snackbar} with a custom text whenever a permission has been + * permanently denied + */ +public class SnackbarOnAnyPermanentlyDeniedMultiplePermissionsListener + extends BaseMultiplePermissionsListener { + + private final View view; + private final String text; + private final String buttonText; + private final View.OnClickListener onButtonClickListener; + private final Snackbar.Callback snackbarCallback; + private final int duration; + + /** + * @param view The view to find a parent from + * @param text Message displayed in the snackbar + * @param buttonText Message displayed in the snackbar button + * @param onButtonClickListener Action performed when the user clicks the snackbar button + */ + private SnackbarOnAnyPermanentlyDeniedMultiplePermissionsListener(View view, String text, + String buttonText, View.OnClickListener onButtonClickListener, + Snackbar.Callback snackbarCallback, int duration) { + this.view = view; + this.text = text; + this.buttonText = buttonText; + this.onButtonClickListener = onButtonClickListener; + this.snackbarCallback = snackbarCallback; + this.duration = duration; + } + + @Override public void onPermissionsChecked(MultiplePermissionsReport report) { + super.onPermissionsChecked(report); + + if (!report.isAnyPermissionPermanentlyDenied()) { + SnackbarUtils.show(view, text, duration, buttonText, onButtonClickListener, snackbarCallback); + } + } + + /** + * Builder class to configure the displayed snackbar + * Non set fields will not be shown + */ + public static class Builder { + private final View view; + private final String text; + private String buttonText; + private View.OnClickListener onClickListener; + private Snackbar.Callback snackbarCallback; + private int duration = Snackbar.LENGTH_LONG; + + private Builder(View view, String text) { + this.view = view; + this.text = text; + } + + public static Builder with(View view, String text) { + return new Builder(view, text); + } + + public static Builder with(View view, @StringRes int textResourceId) { + return Builder.with(view, view.getContext().getString(textResourceId)); + } + + /** + * Adds a text button with the provided click listener + */ + public Builder withButton(String buttonText, View.OnClickListener onClickListener) { + this.buttonText = buttonText; + this.onClickListener = onClickListener; + return this; + } + + /** + * Adds a text button with the provided click listener + */ + public Builder withButton(@StringRes int buttonTextResourceId, + View.OnClickListener onClickListener) { + return withButton(view.getContext().getString(buttonTextResourceId), onClickListener); + } + + /** + * Adds a button that opens the application settings when clicked + */ + public Builder withOpenSettingsButton(String buttonText) { + this.buttonText = buttonText; + this.onClickListener = new SettingsClickListener(); + return this; + } + + /** + * Adds a button that opens the application settings when clicked + */ + public Builder withOpenSettingsButton(@StringRes int buttonTextResourceId) { + return withOpenSettingsButton(view.getContext().getString(buttonTextResourceId)); + } + + /** + * Adds a callback to handle the snackbar {@code onDismissed} and {@code onShown} events. + */ + public Builder withCallback(Snackbar.Callback callback) { + this.snackbarCallback = callback; + return this; + } + + public Builder withDuration(int duration) { + this.duration = duration; + return this; + } + + /** + * Builds a new instance of {@link SnackbarOnAnyPermanentlyDeniedMultiplePermissionsListener} + */ + public SnackbarOnAnyPermanentlyDeniedMultiplePermissionsListener build() { + return new SnackbarOnAnyPermanentlyDeniedMultiplePermissionsListener(view, text, buttonText, + onClickListener, snackbarCallback, duration); + } + } +} diff --git a/dexter/src/main/java/com/karumi/dexter/listener/single/SnackbarOnDeniedPermissionListener.java b/dexter/src/main/java/com/karumi/dexter/listener/single/SnackbarOnDeniedPermissionListener.java index b3d92f43..e2adcc4c 100644 --- a/dexter/src/main/java/com/karumi/dexter/listener/single/SnackbarOnDeniedPermissionListener.java +++ b/dexter/src/main/java/com/karumi/dexter/listener/single/SnackbarOnDeniedPermissionListener.java @@ -16,14 +16,14 @@ package com.karumi.dexter.listener.single; -import android.content.Context; -import android.content.Intent; -import android.net.Uri; -import android.provider.Settings; -import androidx.annotation.StringRes; -import com.google.android.material.snackbar.Snackbar; import android.view.View; + +import com.google.android.material.snackbar.Snackbar; import com.karumi.dexter.listener.PermissionDeniedResponse; +import com.karumi.dexter.listener.SettingsClickListener; +import com.karumi.dexter.listener.SnackbarUtils; + +import androidx.annotation.StringRes; /** * Utility listener that shows a {@link Snackbar} with a custom text whenever a permission has been @@ -57,15 +57,7 @@ private SnackbarOnDeniedPermissionListener(View view, String text, String button @Override public void onPermissionDenied(PermissionDeniedResponse response) { super.onPermissionDenied(response); - - Snackbar snackbar = Snackbar.make(view, text, duration); - if (buttonText != null && onButtonClickListener != null) { - snackbar.setAction(buttonText, onButtonClickListener); - } - if (snackbarCallback != null) { - snackbar.addCallback(snackbarCallback); - } - snackbar.show(); + SnackbarUtils.show(view, text, duration, buttonText, onButtonClickListener, snackbarCallback); } /** @@ -115,16 +107,7 @@ public Builder withButton(@StringRes int buttonTextResourceId, */ public Builder withOpenSettingsButton(String buttonText) { this.buttonText = buttonText; - this.onClickListener = new View.OnClickListener() { - @Override public void onClick(View v) { - Context context = view.getContext(); - Intent myAppSettings = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, - Uri.parse("package:" + context.getPackageName())); - myAppSettings.addCategory(Intent.CATEGORY_DEFAULT); - myAppSettings.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - context.startActivity(myAppSettings); - } - }; + this.onClickListener = new SettingsClickListener(); return this; } diff --git a/dexter/src/main/java/com/karumi/dexter/listener/single/SnackbarOnPermanentlyDeniedPermissionListener.java b/dexter/src/main/java/com/karumi/dexter/listener/single/SnackbarOnPermanentlyDeniedPermissionListener.java new file mode 100644 index 00000000..331e24e2 --- /dev/null +++ b/dexter/src/main/java/com/karumi/dexter/listener/single/SnackbarOnPermanentlyDeniedPermissionListener.java @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2015 Karumi. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.karumi.dexter.listener.single; + +import android.view.View; + +import com.google.android.material.snackbar.Snackbar; +import com.karumi.dexter.listener.PermissionDeniedResponse; +import com.karumi.dexter.listener.SettingsClickListener; +import com.karumi.dexter.listener.SnackbarUtils; + +import androidx.annotation.StringRes; + +/** + * Utility listener that shows a {@link Snackbar} with a custom text whenever a permission has been + * permanently denied + */ +public class SnackbarOnPermanentlyDeniedPermissionListener extends BasePermissionListener { + + private final View view; + private final String text; + private final String buttonText; + private final View.OnClickListener onButtonClickListener; + private final Snackbar.Callback snackbarCallback; + private final int duration; + + /** + * @param view The view to find a parent from + * @param text Message displayed in the snackbar + * @param buttonText Message displayed in the snackbar button + * @param onButtonClickListener Action performed when the user clicks the snackbar button + */ + private SnackbarOnPermanentlyDeniedPermissionListener(View view, String text, String buttonText, + View.OnClickListener onButtonClickListener, Snackbar.Callback snackbarCallback, + int duration) { + this.view = view; + this.text = text; + this.buttonText = buttonText; + this.onButtonClickListener = onButtonClickListener; + this.snackbarCallback = snackbarCallback; + this.duration = duration; + } + + @Override public void onPermissionDenied(PermissionDeniedResponse response) { + super.onPermissionDenied(response); + if (response.isPermanentlyDenied()) { + SnackbarUtils.show(view, text, duration, buttonText, onButtonClickListener, snackbarCallback); + } + } + + /** + * Builder class to configure the displayed snackbar + * Non set fields will not be shown + */ + public static class Builder { + private final View view; + private final String text; + private String buttonText; + private View.OnClickListener onClickListener; + private Snackbar.Callback snackbarCallback; + private int duration = Snackbar.LENGTH_LONG; + + private Builder(View view, String text) { + this.view = view; + this.text = text; + } + + public static Builder with(View view, String text) { + return new Builder(view, text); + } + + public static Builder with(View view, @StringRes int textResourceId) { + return Builder.with(view, view.getContext().getString(textResourceId)); + } + + /** + * Adds a text button with the provided click listener + */ + public Builder withButton(String buttonText, View.OnClickListener onClickListener) { + this.buttonText = buttonText; + this.onClickListener = onClickListener; + return this; + } + + /** + * Adds a text button with the provided click listener + */ + public Builder withButton(@StringRes int buttonTextResourceId, + View.OnClickListener onClickListener) { + return withButton(view.getContext().getString(buttonTextResourceId), onClickListener); + } + + /** + * Adds a button that opens the application settings when clicked + */ + public Builder withOpenSettingsButton(String buttonText) { + this.buttonText = buttonText; + this.onClickListener = new SettingsClickListener(); + return this; + } + + /** + * Adds a button that opens the application settings when clicked + */ + public Builder withOpenSettingsButton(@StringRes int buttonTextResourceId) { + return withOpenSettingsButton(view.getContext().getString(buttonTextResourceId)); + } + + /** + * Adds a callback to handle the snackbar {@code onDismissed} and {@code onShown} events + */ + public Builder withCallback(Snackbar.Callback callback) { + this.snackbarCallback = callback; + return this; + } + + /** + * Adds the duration of the snackbar on the screen + */ + public Builder withDuration(int duration) { + this.duration = duration; + return this; + } + + /** + * Builds a new instance of {@link SnackbarOnPermanentlyDeniedPermissionListener} + */ + public SnackbarOnPermanentlyDeniedPermissionListener build() { + return new SnackbarOnPermanentlyDeniedPermissionListener(view, text, buttonText, onClickListener, + snackbarCallback, duration); + } + } +}