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