1 /* 2 * Copyright (C) 2024 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.settings.connecteddevice.audiosharing; 18 19 import android.content.Context; 20 import android.content.DialogInterface; 21 import android.view.LayoutInflater; 22 import android.view.View; 23 import android.widget.Button; 24 import android.widget.ImageView; 25 import android.widget.TextView; 26 27 import androidx.annotation.DrawableRes; 28 import androidx.annotation.NonNull; 29 import androidx.annotation.StringRes; 30 import androidx.appcompat.app.AlertDialog; 31 import androidx.recyclerview.widget.LinearLayoutManager; 32 import androidx.recyclerview.widget.RecyclerView; 33 34 import com.android.settings.R; 35 36 import javax.annotation.CheckReturnValue; 37 38 public class AudioSharingDialogFactory { 39 private static final String TAG = "AudioSharingDialogFactory"; 40 41 /** 42 * Initializes a builder for the dialog to be shown for audio sharing. 43 * 44 * @param context The {@link Context} that will be used to create the dialog. 45 * @return A configurable builder for the dialog. 46 */ 47 @NonNull newBuilder(@onNull Context context)48 public static AudioSharingDialogFactory.DialogBuilder newBuilder(@NonNull Context context) { 49 return new AudioSharingDialogFactory.DialogBuilder(context); 50 } 51 52 /** Builder class with configurable options for the dialog to be shown for audio sharing. */ 53 public static class DialogBuilder { 54 private Context mContext; 55 private AlertDialog.Builder mBuilder; 56 private View mCustomTitle; 57 private View mCustomBody; 58 private boolean mIsCustomBodyEnabled; 59 60 /** 61 * Private constructor for the dialog builder class. Should not be invoked directly; 62 * instead, use {@link AudioSharingDialogFactory#newBuilder(Context)}. 63 * 64 * @param context The {@link Context} that will be used to create the dialog. 65 */ DialogBuilder(@onNull Context context)66 private DialogBuilder(@NonNull Context context) { 67 mContext = context; 68 mBuilder = new AlertDialog.Builder(context); 69 LayoutInflater inflater = LayoutInflater.from(mBuilder.getContext()); 70 mCustomTitle = 71 inflater.inflate(R.layout.dialog_custom_title_audio_sharing, /* root= */ null); 72 mCustomBody = 73 inflater.inflate(R.layout.dialog_custom_body_audio_sharing, /* parent= */ null); 74 } 75 76 /** 77 * Sets title of the dialog custom title. 78 * 79 * @param titleRes Resource ID of the string to be used for the dialog title. 80 * @return This builder. 81 */ 82 @NonNull setTitle(@tringRes int titleRes)83 public AudioSharingDialogFactory.DialogBuilder setTitle(@StringRes int titleRes) { 84 TextView title = mCustomTitle.findViewById(R.id.title_text); 85 title.setText(titleRes); 86 return this; 87 } 88 89 /** 90 * Sets title of the dialog custom title. 91 * 92 * @param titleText The text to be used for the title. 93 * @return This builder. 94 */ 95 @NonNull setTitle(@onNull CharSequence titleText)96 public AudioSharingDialogFactory.DialogBuilder setTitle(@NonNull CharSequence titleText) { 97 TextView title = mCustomTitle.findViewById(R.id.title_text); 98 title.setText(titleText); 99 return this; 100 } 101 102 /** 103 * Sets the title icon of the dialog custom title. 104 * 105 * @param iconRes The text to be used for the title. 106 * @return This builder. 107 */ 108 @NonNull setTitleIcon(@rawableRes int iconRes)109 public AudioSharingDialogFactory.DialogBuilder setTitleIcon(@DrawableRes int iconRes) { 110 ImageView icon = mCustomTitle.findViewById(R.id.title_icon); 111 icon.setImageResource(iconRes); 112 return this; 113 } 114 115 /** 116 * Sets the message body of the dialog. 117 * 118 * @param messageRes Resource ID of the string to be used for the message body. 119 * @return This builder. 120 */ 121 @NonNull setMessage(@tringRes int messageRes)122 public AudioSharingDialogFactory.DialogBuilder setMessage(@StringRes int messageRes) { 123 mBuilder.setMessage(messageRes); 124 return this; 125 } 126 127 /** 128 * Sets the message body of the dialog. 129 * 130 * @param message The text to be used for the message body. 131 * @return This builder. 132 */ 133 @NonNull setMessage(@onNull CharSequence message)134 public AudioSharingDialogFactory.DialogBuilder setMessage(@NonNull CharSequence message) { 135 mBuilder.setMessage(message); 136 return this; 137 } 138 139 /** Whether to use custom body. */ 140 @NonNull setIsCustomBodyEnabled( boolean isCustomBodyEnabled)141 public AudioSharingDialogFactory.DialogBuilder setIsCustomBodyEnabled( 142 boolean isCustomBodyEnabled) { 143 mIsCustomBodyEnabled = isCustomBodyEnabled; 144 return this; 145 } 146 147 /** 148 * Sets the custom image of the dialog custom body. 149 * 150 * @param iconRes The text to be used for the title. 151 * @return This builder. 152 */ 153 @NonNull setCustomImage(@rawableRes int iconRes)154 public AudioSharingDialogFactory.DialogBuilder setCustomImage(@DrawableRes int iconRes) { 155 ImageView image = mCustomBody.findViewById(R.id.description_image); 156 image.setImageResource(iconRes); 157 image.setVisibility(View.VISIBLE); 158 return this; 159 } 160 161 /** 162 * Sets the custom message of the dialog custom body. 163 * 164 * @param messageRes Resource ID of the string to be used for the message body. 165 * @return This builder. 166 */ 167 @NonNull setCustomMessage(@tringRes int messageRes)168 public AudioSharingDialogFactory.DialogBuilder setCustomMessage(@StringRes int messageRes) { 169 TextView subTitle = mCustomBody.findViewById(R.id.description_text); 170 subTitle.setText(messageRes); 171 subTitle.setVisibility(View.VISIBLE); 172 return this; 173 } 174 175 /** 176 * Sets the custom message of the dialog custom body. 177 * 178 * @param message The text to be used for the custom message body. 179 * @return This builder. 180 */ 181 @NonNull setCustomMessage( @onNull CharSequence message)182 public AudioSharingDialogFactory.DialogBuilder setCustomMessage( 183 @NonNull CharSequence message) { 184 TextView subTitle = mCustomBody.findViewById(R.id.description_text); 185 subTitle.setText(message); 186 subTitle.setVisibility(View.VISIBLE); 187 return this; 188 } 189 190 /** 191 * Sets the custom device actions of the dialog custom body. 192 * 193 * @param adapter The adapter for device items to build dialog actions. 194 * @return This builder. 195 */ 196 @NonNull setCustomDeviceActions( @onNull AudioSharingDeviceAdapter adapter)197 public AudioSharingDialogFactory.DialogBuilder setCustomDeviceActions( 198 @NonNull AudioSharingDeviceAdapter adapter) { 199 RecyclerView recyclerView = mCustomBody.findViewById(R.id.device_btn_list); 200 recyclerView.setAdapter(adapter); 201 recyclerView.setLayoutManager( 202 new LinearLayoutManager(mContext, LinearLayoutManager.VERTICAL, false)); 203 recyclerView.setVisibility(View.VISIBLE); 204 return this; 205 } 206 207 /** 208 * Sets the positive button label and listener for the dialog. 209 * 210 * @param labelRes Resource ID of the string to be used for the positive button label. 211 * @param listener The listener to be invoked when the positive button is pressed. 212 * @return This builder. 213 */ 214 @NonNull setPositiveButton( @tringRes int labelRes, @NonNull DialogInterface.OnClickListener listener)215 public AudioSharingDialogFactory.DialogBuilder setPositiveButton( 216 @StringRes int labelRes, @NonNull DialogInterface.OnClickListener listener) { 217 mBuilder.setPositiveButton(labelRes, listener); 218 return this; 219 } 220 221 /** 222 * Sets the positive button label and listener for the dialog. 223 * 224 * @param label The text to be used for the positive button label. 225 * @param listener The listener to be invoked when the positive button is pressed. 226 * @return This builder. 227 */ 228 @NonNull setPositiveButton( @onNull CharSequence label, @NonNull DialogInterface.OnClickListener listener)229 public AudioSharingDialogFactory.DialogBuilder setPositiveButton( 230 @NonNull CharSequence label, @NonNull DialogInterface.OnClickListener listener) { 231 mBuilder.setPositiveButton(label, listener); 232 return this; 233 } 234 235 /** 236 * Sets the custom positive button label and listener for the dialog custom body. 237 * 238 * @param labelRes Resource ID of the string to be used for the positive button label. 239 * @param listener The listener to be invoked when the positive button is pressed. 240 * @return This builder. 241 */ 242 @NonNull setCustomPositiveButton( @tringRes int labelRes, @NonNull View.OnClickListener listener)243 public AudioSharingDialogFactory.DialogBuilder setCustomPositiveButton( 244 @StringRes int labelRes, @NonNull View.OnClickListener listener) { 245 Button positiveBtn = mCustomBody.findViewById(R.id.positive_btn); 246 positiveBtn.setText(labelRes); 247 positiveBtn.setOnClickListener(listener); 248 positiveBtn.setVisibility(View.VISIBLE); 249 return this; 250 } 251 252 /** 253 * Sets the custom positive button label and listener for the dialog custom body. 254 * 255 * @param label The text to be used for the positive button label. 256 * @param listener The listener to be invoked when the positive button is pressed. 257 * @return This builder. 258 */ 259 @NonNull setCustomPositiveButton( @onNull CharSequence label, @NonNull View.OnClickListener listener)260 public AudioSharingDialogFactory.DialogBuilder setCustomPositiveButton( 261 @NonNull CharSequence label, @NonNull View.OnClickListener listener) { 262 Button positiveBtn = mCustomBody.findViewById(R.id.positive_btn); 263 positiveBtn.setText(label); 264 positiveBtn.setOnClickListener(listener); 265 positiveBtn.setVisibility(View.VISIBLE); 266 return this; 267 } 268 269 /** 270 * Sets the negative button label and listener for the dialog. 271 * 272 * @param labelRes Resource ID of the string to be used for the negative button label. 273 * @param listener The listener to be invoked when the negative button is pressed. 274 * @return This builder. 275 */ 276 @NonNull setNegativeButton( @tringRes int labelRes, @NonNull DialogInterface.OnClickListener listener)277 public AudioSharingDialogFactory.DialogBuilder setNegativeButton( 278 @StringRes int labelRes, @NonNull DialogInterface.OnClickListener listener) { 279 mBuilder.setNegativeButton(labelRes, listener); 280 return this; 281 } 282 283 /** 284 * Sets the negative button label and listener for the dialog. 285 * 286 * @param label The text to be used for the negative button label. 287 * @param listener The listener to be invoked when the negative button is pressed. 288 * @return This builder. 289 */ 290 @NonNull setNegativeButton( @onNull CharSequence label, @NonNull DialogInterface.OnClickListener listener)291 public AudioSharingDialogFactory.DialogBuilder setNegativeButton( 292 @NonNull CharSequence label, @NonNull DialogInterface.OnClickListener listener) { 293 mBuilder.setNegativeButton(label, listener); 294 return this; 295 } 296 297 /** 298 * Sets the custom negative button label and listener for the dialog custom body. 299 * 300 * @param labelRes Resource ID of the string to be used for the negative button label. 301 * @param listener The listener to be invoked when the negative button is pressed. 302 * @return This builder. 303 */ 304 @NonNull setCustomNegativeButton( @tringRes int labelRes, @NonNull View.OnClickListener listener)305 public AudioSharingDialogFactory.DialogBuilder setCustomNegativeButton( 306 @StringRes int labelRes, @NonNull View.OnClickListener listener) { 307 Button negativeBtn = mCustomBody.findViewById(R.id.negative_btn); 308 negativeBtn.setText(labelRes); 309 negativeBtn.setOnClickListener(listener); 310 negativeBtn.setVisibility(View.VISIBLE); 311 return this; 312 } 313 314 /** 315 * Sets the custom negative button label and listener for the dialog custom body. 316 * 317 * @param label The text to be used for the negative button label. 318 * @param listener The listener to be invoked when the negative button is pressed. 319 * @return This builder. 320 */ 321 @NonNull setCustomNegativeButton( @onNull CharSequence label, @NonNull View.OnClickListener listener)322 public AudioSharingDialogFactory.DialogBuilder setCustomNegativeButton( 323 @NonNull CharSequence label, @NonNull View.OnClickListener listener) { 324 Button negativeBtn = mCustomBody.findViewById(R.id.negative_btn); 325 negativeBtn.setText(label); 326 negativeBtn.setOnClickListener(listener); 327 negativeBtn.setVisibility(View.VISIBLE); 328 return this; 329 } 330 331 /** 332 * Builds a dialog with the current configs. 333 * 334 * @return The dialog to be shown for audio sharing. 335 */ 336 @NonNull 337 @CheckReturnValue build()338 public AlertDialog build() { 339 if (mIsCustomBodyEnabled) { 340 mBuilder.setView(mCustomBody); 341 } 342 final AlertDialog dialog = 343 mBuilder.setCustomTitle(mCustomTitle).setCancelable(false).create(); 344 dialog.setCanceledOnTouchOutside(false); 345 return dialog; 346 } 347 } 348 AudioSharingDialogFactory()349 private AudioSharingDialogFactory() {} 350 } 351