1 /* 2 * Copyright 2016, The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.managedprovisioning.common; 18 19 import android.app.Activity; 20 import android.app.AlertDialog; 21 import android.app.DialogFragment; 22 import android.os.Bundle; 23 24 import androidx.annotation.StringRes; 25 26 import com.android.managedprovisioning.util.LazyStringResource; 27 28 /** 29 * Utility class wrapping a {@link AlertDialog} in a {@link DialogFragment} 30 * <p> In order to properly handle Dialog lifecycle we follow the practice of wrapping of them 31 * in a Dialog Fragment. 32 * <p> If buttons are to be used (enabled by setting a button message), the creator {@link Activity} 33 * must implement {@link SimpleDialogListener}. 34 */ 35 public class SimpleDialog extends DialogFragment { 36 private static final String TITLE = "title"; 37 private static final String MESSAGE = "message"; 38 private static final String LOCALIZED_MESSAGE = "localized_message"; 39 private static final String NEGATIVE_BUTTON_MESSAGE = "negativeButtonMessage"; 40 private static final String POSITIVE_BUTTON_MESSAGE = "positiveButtonMessage"; 41 42 /** 43 * Use the {@link Builder} instead. Keeping the constructor public only because 44 * a {@link DialogFragment} must have an empty constructor that is public. 45 */ SimpleDialog()46 public SimpleDialog() { 47 } 48 49 @Override onCreateDialog(Bundle savedInstanceState)50 public AlertDialog onCreateDialog(Bundle savedInstanceState) { 51 var context = getContext(); 52 final SimpleDialogListener dialogListener = (SimpleDialogListener) getActivity(); 53 54 AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); 55 56 Bundle args = getArguments(); 57 if (args.containsKey(TITLE)) { 58 builder.setTitle(LazyStringResource.of(args.getBundle(TITLE)).value(context)); 59 } 60 61 if (args.containsKey(MESSAGE)) { 62 builder.setMessage(LazyStringResource.of(args.getBundle(MESSAGE)).value(context)); 63 } 64 65 if (args.containsKey(NEGATIVE_BUTTON_MESSAGE)) { 66 builder.setNegativeButton( 67 LazyStringResource.of(args.getBundle(NEGATIVE_BUTTON_MESSAGE)).value(context), 68 (dialog, which) -> dialogListener.onNegativeButtonClick(SimpleDialog.this)); 69 } 70 71 if (args.containsKey(POSITIVE_BUTTON_MESSAGE)) { 72 builder.setPositiveButton( 73 LazyStringResource.of(args.getBundle(POSITIVE_BUTTON_MESSAGE)).value(context), 74 (dialog, which) -> dialogListener.onPositiveButtonClick(SimpleDialog.this)); 75 } 76 77 return builder.create(); 78 } 79 80 /** 81 * Throws an exception informing of a lack of a handler for a dialog button click 82 * <p> Useful when implementing {@link SimpleDialogListener} 83 */ throwButtonClickHandlerNotImplemented(DialogFragment dialog)84 public static void throwButtonClickHandlerNotImplemented(DialogFragment dialog) { 85 throw new IllegalArgumentException("Button click handler not implemented for dialog: " 86 + dialog.getTag()); 87 } 88 89 /** 90 * A builder for SimpleDialog 91 */ 92 public static class Builder implements DialogBuilder { 93 private LazyStringResource mTitle; 94 private LazyStringResource mMessage; 95 private LazyStringResource mNegativeButtonMessage; 96 private LazyStringResource mPositiveButtonMessage; 97 private Boolean mCancelable; 98 99 /** 100 * Sets the title 101 * 102 * @param title Title resource. 103 */ setTitle(LazyStringResource title)104 public Builder setTitle(LazyStringResource title) { 105 this.mTitle = title; 106 return this; 107 } 108 109 /** 110 * Sets the title 111 * 112 * @param titleId Title resource id. 113 */ setTitle(@tringRes int titleId)114 public Builder setTitle(@StringRes int titleId) { 115 return setTitle(LazyStringResource.of(titleId)); 116 } 117 118 /** 119 * Sets the message 120 * 121 * @param message Message resource. 122 */ setMessage(LazyStringResource message)123 public Builder setMessage(LazyStringResource message) { 124 this.mMessage = message; 125 return this; 126 } 127 128 /** 129 * Sets the message 130 * 131 * @param messageId Message resource id. 132 */ setMessage(@tringRes int messageId)133 public Builder setMessage(@StringRes int messageId) { 134 return setMessage(LazyStringResource.of(messageId)); 135 } 136 137 /** 138 * Sets a message for the button. 139 * 140 * <p>Makes the button appear (without setting a button message, a button is not displayed) 141 * 142 * <p>Callback must be handled by a creator {@link Activity}, which must implement {@link 143 * SimpleDialogListener}. 144 * 145 * @param negativeButtonMessage Message resource. 146 */ setNegativeButtonMessage(LazyStringResource negativeButtonMessage)147 public Builder setNegativeButtonMessage(LazyStringResource negativeButtonMessage) { 148 this.mNegativeButtonMessage = negativeButtonMessage; 149 return this; 150 } 151 152 /** 153 * Sets a message for the button. 154 * 155 * <p>Makes the button appear (without setting a button message, a button is not displayed) 156 * 157 * <p>Callback must be handled by a creator {@link Activity}, which must implement {@link 158 * SimpleDialogListener}. 159 * 160 * @param negativeButtonMessageId Message resource id. 161 */ setNegativeButtonMessage(@tringRes int negativeButtonMessageId)162 public Builder setNegativeButtonMessage(@StringRes int negativeButtonMessageId) { 163 return setNegativeButtonMessage(LazyStringResource.of(negativeButtonMessageId)); 164 } 165 166 /** 167 * Sets a message for the button. 168 * 169 * <p>Makes the button appear (without setting a button message, a button is not displayed) 170 * 171 * <p>Callback must be handled by a creator {@link Activity}, which must implement {@link 172 * SimpleDialogListener}. 173 * 174 * @param positiveButtonMessage Message resource. 175 */ setPositiveButtonMessage(LazyStringResource positiveButtonMessage)176 public Builder setPositiveButtonMessage(LazyStringResource positiveButtonMessage) { 177 this.mPositiveButtonMessage = positiveButtonMessage; 178 return this; 179 } 180 181 /** 182 * Sets a message for the button. 183 * 184 * <p>Makes the button appear (without setting a button message, a button is not displayed) 185 * 186 * <p>Callback must be handled by a creator {@link Activity}, which must implement {@link 187 * SimpleDialogListener}. 188 * 189 * @param positiveButtonMessageId Message resource id. 190 */ setPositiveButtonMessage(@tringRes int positiveButtonMessageId)191 public Builder setPositiveButtonMessage(@StringRes int positiveButtonMessageId) { 192 return setPositiveButtonMessage(LazyStringResource.of(positiveButtonMessageId)); 193 } 194 195 /** Sets whether the dialog is cancelable or not. Default is true. */ setCancelable(boolean cancelable)196 public Builder setCancelable(boolean cancelable) { 197 mCancelable = cancelable; 198 return this; 199 } 200 201 /** Creates an {@link SimpleDialog} with the arguments supplied to this builder. */ 202 @Override build()203 public SimpleDialog build() { 204 SimpleDialog instance = new SimpleDialog(); 205 Bundle args = new Bundle(); 206 207 if (mTitle != null) { 208 args.putBundle(TITLE, mTitle.toBundle()); 209 } 210 211 if (mMessage != null) { 212 args.putBundle(MESSAGE, mMessage.toBundle()); 213 } 214 215 if (mNegativeButtonMessage != null) { 216 args.putBundle(NEGATIVE_BUTTON_MESSAGE, mNegativeButtonMessage.toBundle()); 217 } 218 219 if (mPositiveButtonMessage != null) { 220 args.putBundle(POSITIVE_BUTTON_MESSAGE, mPositiveButtonMessage.toBundle()); 221 } 222 223 if (mCancelable != null) { 224 instance.setCancelable(mCancelable); 225 } 226 227 instance.setArguments(args); 228 return instance; 229 } 230 } 231 232 /** 233 * Interface for handling callbacks from {@link SimpleDialog} buttons. 234 * 235 * <p>If multiple dialogs are used in a context of a single {@link Activity}, 236 * a consumer of the interface can differentiate between dialogs using 237 * e.g. a {@link DialogFragment#getTag()}, or {@link DialogFragment#getArguments()}. 238 */ 239 public interface SimpleDialogListener { 240 /** 241 * Called when a user clicks on the positive dialog button. 242 * <p> To be implemented by a host {@link Activity} object. 243 * @param dialog {@link DialogFragment} where the click happened. 244 */ onPositiveButtonClick(DialogFragment dialog)245 void onPositiveButtonClick(DialogFragment dialog); 246 247 /** 248 * Called when a user clicks on the negative dialog button. 249 * <p> To be implemented by a host {@link Activity} object. 250 * @param dialog {@link DialogFragment} where the click happened. 251 */ onNegativeButtonClick(DialogFragment dialog)252 void onNegativeButtonClick(DialogFragment dialog); 253 } 254 } 255