blob: 90be0c61084a179b2eca4f86517d891b5bf9af0c [file] [log] [blame]
/*
* Copyright (C) 2019 The Android Open Source Project
*
* 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.android.car.settings.common;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.Parcelable;
import android.text.TextUtils;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import com.android.car.ui.AlertDialogBuilder;
import com.android.car.ui.preference.CarUiDialogFragment;
/**
* Common dialog that can be used across the settings app to ask the user to confirm their desired
* action.
*/
public class ConfirmationDialogFragment extends CarUiDialogFragment {
/** Builder to help construct {@link ConfirmationDialogFragment}. */
public static class Builder {
private final Context mContext;
private Bundle mArgs;
private String mTitle;
private String mMessage;
private String mPosLabel;
private String mNegLabel;
private String mNeuLabel;
private ConfirmListener mConfirmListener;
private RejectListener mRejectListener;
private NeutralListener mNeutralListener;
private DismissListener mDismissListener;
public Builder(Context context) {
mContext = context;
}
/** Sets the title. */
public Builder setTitle(String title) {
mTitle = title;
return this;
}
/** Sets the title. */
public Builder setTitle(@StringRes int title) {
mTitle = mContext.getString(title);
return this;
}
/** Sets the message. */
public Builder setMessage(String message) {
mMessage = message;
return this;
}
/** Sets the message. */
public Builder setMessage(@StringRes int message) {
mMessage = mContext.getString(message);
return this;
}
/** Sets the positive button label. */
public Builder setPositiveButton(String label, ConfirmListener confirmListener) {
mPosLabel = label;
mConfirmListener = confirmListener;
return this;
}
/** Sets the positive button label. */
public Builder setPositiveButton(@StringRes int label, ConfirmListener confirmListener) {
mPosLabel = mContext.getString(label);
mConfirmListener = confirmListener;
return this;
}
/** Sets the negative button label. */
public Builder setNegativeButton(String label, RejectListener rejectListener) {
mNegLabel = label;
mRejectListener = rejectListener;
return this;
}
/** Sets the negative button label. */
public Builder setNegativeButton(@StringRes int label, RejectListener rejectListener) {
mNegLabel = mContext.getString(label);
mRejectListener = rejectListener;
return this;
}
/** Sets the neutral button label. */
public Builder setNeutralButton(@StringRes int label, NeutralListener neutralListener) {
mNeuLabel = mContext.getString(label);
mNeutralListener = neutralListener;
return this;
}
/** Sets the listener for dialog dismiss. */
public Builder setDismissListener(DismissListener dismissListener) {
mDismissListener = dismissListener;
return this;
}
/** Adds an argument string to the argument bundle. */
public Builder addArgumentString(String argumentKey, String argument) {
if (mArgs == null) {
mArgs = new Bundle();
}
mArgs.putString(argumentKey, argument);
return this;
}
/** Adds an argument long to the argument bundle. */
public Builder addArgumentLong(String argumentKey, long argument) {
if (mArgs == null) {
mArgs = new Bundle();
}
mArgs.putLong(argumentKey, argument);
return this;
}
/** Adds an argument boolean to the argument bundle. */
public Builder addArgumentBoolean(String argumentKey, boolean argument) {
if (mArgs == null) {
mArgs = new Bundle();
}
mArgs.putBoolean(argumentKey, argument);
return this;
}
/** Adds an argument Parcelable to the argument bundle. */
public Builder addArgumentParcelable(String argumentKey, Parcelable argument) {
if (mArgs == null) {
mArgs = new Bundle();
}
mArgs.putParcelable(argumentKey, argument);
return this;
}
/** Constructs the {@link ConfirmationDialogFragment}. */
public ConfirmationDialogFragment build() {
return ConfirmationDialogFragment.init(this);
}
}
/** Identifier used to launch the dialog fragment. */
public static final String TAG = "ConfirmationDialogFragment";
// Argument keys are prefixed with TAG in order to reduce the changes of collision with user
// provided arguments.
private static final String ALL_ARGUMENTS_KEY = TAG + "_all_arguments";
private static final String ARGUMENTS_KEY = TAG + "_arguments";
private static final String TITLE_KEY = TAG + "_title";
private static final String MESSAGE_KEY = TAG + "_message";
private static final String POSITIVE_KEY = TAG + "_positive";
private static final String NEGATIVE_KEY = TAG + "_negative";
private static final String NEUTRAL_KEY = TAG + "_neutral";
private String mTitle;
private String mMessage;
private String mPosLabel;
private String mNegLabel;
private String mNeuLabel;
private ConfirmListener mConfirmListener;
private RejectListener mRejectListener;
private NeutralListener mNeutralListener;
private DismissListener mDismissListener;
/** Constructs the dialog fragment from the arguments provided in the {@link Builder} */
private static ConfirmationDialogFragment init(Builder builder) {
ConfirmationDialogFragment dialogFragment = new ConfirmationDialogFragment();
Bundle args = new Bundle();
args.putBundle(ARGUMENTS_KEY, builder.mArgs);
args.putString(TITLE_KEY, builder.mTitle);
args.putString(MESSAGE_KEY, builder.mMessage);
args.putString(POSITIVE_KEY, builder.mPosLabel);
args.putString(NEGATIVE_KEY, builder.mNegLabel);
args.putString(NEUTRAL_KEY, builder.mNeuLabel);
dialogFragment.setArguments(args);
dialogFragment.setConfirmListener(builder.mConfirmListener);
dialogFragment.setRejectListener(builder.mRejectListener);
dialogFragment.setNeutralListener(builder.mNeutralListener);
dialogFragment.setDismissListener(builder.mDismissListener);
return dialogFragment;
}
/**
* Since it is possible for the listeners to be unregistered on configuration change, provide a
* way to reattach the listeners.
*/
public static void resetListeners(@Nullable ConfirmationDialogFragment dialogFragment,
@Nullable ConfirmListener confirmListener,
@Nullable RejectListener rejectListener,
@Nullable NeutralListener neutralListener) {
if (dialogFragment != null) {
dialogFragment.setConfirmListener(confirmListener);
dialogFragment.setRejectListener(rejectListener);
dialogFragment.setNeutralListener(neutralListener);
}
}
/** Sets the listeners which listens for the dialog dismissed */
public void setDismissListener(DismissListener dismissListener) {
mDismissListener = dismissListener;
}
/** Gets the listener which listens for the dialog dismissed */
@Nullable
public DismissListener getDismissListener() {
return mDismissListener;
}
/** Sets the listener which listens to a click on the positive button. */
private void setConfirmListener(ConfirmListener confirmListener) {
mConfirmListener = confirmListener;
}
/** Gets the listener which listens to a click on the positive button */
@Nullable
public ConfirmListener getConfirmListener() {
return mConfirmListener;
}
/** Sets the listener which listens to a click on the negative button. */
private void setRejectListener(RejectListener rejectListener) {
mRejectListener = rejectListener;
}
/** Gets the listener which listens to a click on the negative button. */
@Nullable
public RejectListener getRejectListener() {
return mRejectListener;
}
/** Sets the listener which listens to a click on the neutral button. */
private void setNeutralListener(NeutralListener neutralListener) {
mNeutralListener = neutralListener;
}
/** Gets the listener which listens to a click on the neutral button. */
@Nullable
public NeutralListener getNeutralListener() {
return mNeutralListener;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle args = getArguments();
if (savedInstanceState != null) {
args = savedInstanceState.getBundle(ALL_ARGUMENTS_KEY);
}
if (args != null) {
mTitle = getArguments().getString(TITLE_KEY);
mMessage = getArguments().getString(MESSAGE_KEY);
mPosLabel = getArguments().getString(POSITIVE_KEY);
mNegLabel = getArguments().getString(NEGATIVE_KEY);
mNeuLabel = getArguments().getString(NEUTRAL_KEY);
}
}
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBundle(ALL_ARGUMENTS_KEY, getArguments());
}
@NonNull
@Override
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
AlertDialogBuilder builder = new AlertDialogBuilder(getContext());
if (!TextUtils.isEmpty(mTitle)) {
builder.setTitle(mTitle);
}
if (!TextUtils.isEmpty(mMessage)) {
builder.setMessage(mMessage);
}
if (!TextUtils.isEmpty(mPosLabel)) {
builder.setPositiveButton(mPosLabel, this);
}
if (!TextUtils.isEmpty(mNegLabel)) {
builder.setNegativeButton(mNegLabel, this);
}
if (!TextUtils.isEmpty(mNeuLabel)) {
builder.setNeutralButton(mNeuLabel, this);
}
return builder.create();
}
@Override
protected void onDialogClosed(boolean positiveResult) {
if (mDismissListener != null) {
mDismissListener.onDismiss(getArguments().getBundle(ARGUMENTS_KEY), positiveResult);
}
}
@Override
public void onClick(DialogInterface dialog, int which) {
super.onClick(dialog, which);
if (which == DialogInterface.BUTTON_POSITIVE) {
if (mConfirmListener != null) {
mConfirmListener.onConfirm(getArguments().getBundle(ARGUMENTS_KEY));
}
} else if (which == DialogInterface.BUTTON_NEGATIVE) {
if (mRejectListener != null) {
mRejectListener.onReject(getArguments().getBundle(ARGUMENTS_KEY));
}
} else if (which == DialogInterface.BUTTON_NEUTRAL) {
if (mNeutralListener != null) {
mNeutralListener.onNeutral(getArguments().getBundle(ARGUMENTS_KEY));
}
}
}
/** Listens to the confirmation action. */
public interface ConfirmListener {
/**
* Defines the action to take on confirm. The bundle will contain the arguments added when
* constructing the dialog through with {@link Builder#addArgumentString(String, String)}.
*/
void onConfirm(@Nullable Bundle arguments);
}
/** Listens to the rejection action. */
public interface RejectListener {
/**
* Defines the action to take on reject. The bundle will contain the arguments added when
* constructing the dialog through with {@link Builder#addArgumentString(String, String)}.
*/
void onReject(@Nullable Bundle arguments);
}
/** Listens to the neutral button action. */
public interface NeutralListener {
/**
* Defines the action to take on neutral button click. The bundle will contain the arguments
* added when constructing the dialog through with
* {@link Builder#addArgumentString(String, String)}.
*/
void onNeutral(@Nullable Bundle arguments);
}
/** Listens to the dismiss action. */
public interface DismissListener {
/**
* Defines the action to take when the dialog is closed.
* @param arguments - bundle containing the arguments added when constructing the dialog
* through with {@link Builder#addArgumentString(String, String)}.
* @param positiveResult - whether or not the dialog was dismissed because of a positive
* button press.
*/
void onDismiss(@Nullable Bundle arguments, boolean positiveResult);
}
}