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.audiostreams;
18 
19 import android.app.AlertDialog;
20 import android.app.Dialog;
21 import android.app.settings.SettingsEnums;
22 import android.content.Context;
23 import android.os.Bundle;
24 import android.util.Log;
25 import android.view.LayoutInflater;
26 import android.view.View;
27 import android.widget.Button;
28 import android.widget.TextView;
29 
30 import androidx.annotation.NonNull;
31 import androidx.annotation.Nullable;
32 import androidx.fragment.app.DialogFragment;
33 import androidx.fragment.app.Fragment;
34 import androidx.fragment.app.FragmentManager;
35 
36 import com.android.settings.R;
37 import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
38 
39 import com.google.common.base.Strings;
40 
41 import java.util.function.Consumer;
42 
43 /** A dialog fragment for constructing and showing audio stream dialogs. */
44 public class AudioStreamsDialogFragment extends InstrumentedDialogFragment {
45     private static final String TAG = "AudioStreamsDialogFragment";
46     private final DialogBuilder mDialogBuilder;
47     private int mDialogId = SettingsEnums.PAGE_UNKNOWN;
48 
AudioStreamsDialogFragment(DialogBuilder dialogBuilder, int dialogId)49     AudioStreamsDialogFragment(DialogBuilder dialogBuilder, int dialogId) {
50         mDialogBuilder = dialogBuilder;
51         mDialogId = dialogId;
52     }
53 
54     @Override
getMetricsCategory()55     public int getMetricsCategory() {
56         return mDialogId;
57     }
58 
59     @Override
onCreateDialog(Bundle savedInstanceState)60     public Dialog onCreateDialog(Bundle savedInstanceState) {
61         return mDialogBuilder.build();
62     }
63 
64     /**
65      * Displays the audio stream dialog on the specified host fragment.
66      *
67      * @param host The fragment to host the dialog.
68      * @param dialogBuilder The builder for constructing the dialog.
69      * @param dialogId The dialog settings enum for logging
70      */
show(Fragment host, DialogBuilder dialogBuilder, int dialogId)71     public static void show(Fragment host, DialogBuilder dialogBuilder, int dialogId) {
72         if (!host.isAdded()) {
73             Log.w(TAG, "The host fragment is not added to the activity!");
74             return;
75         }
76         FragmentManager manager = host.getChildFragmentManager();
77         (new AudioStreamsDialogFragment(dialogBuilder, dialogId)).show(manager, TAG);
78     }
79 
dismissAll(Fragment host)80     static void dismissAll(Fragment host) {
81         if (!host.isAdded()) {
82             Log.w(TAG, "The host fragment is not added to the activity!");
83             return;
84         }
85         FragmentManager manager = host.getChildFragmentManager();
86         Fragment dialog = manager.findFragmentByTag(TAG);
87         if (dialog != null
88                 && ((DialogFragment) dialog).getDialog() != null
89                 && ((DialogFragment) dialog).getDialog().isShowing()) {
90             ((DialogFragment) dialog).dismiss();
91         }
92     }
93 
94     @Override
show(@onNull FragmentManager manager, @Nullable String tag)95     public void show(@NonNull FragmentManager manager, @Nullable String tag) {
96         Fragment dialog = manager.findFragmentByTag(TAG);
97         if (dialog != null
98                 && ((DialogFragment) dialog).getDialog() != null
99                 && ((DialogFragment) dialog).getDialog().isShowing()) {
100             Log.w(TAG, "Dialog already showing, ignore");
101             return;
102         }
103         super.show(manager, tag);
104     }
105 
106     /** A builder class for constructing the audio stream dialog. */
107     public static class DialogBuilder {
108         private final Context mContext;
109         private final AlertDialog.Builder mBuilder;
110         @Nullable private String mTitle;
111         @Nullable private String mSubTitle1;
112         @Nullable private String mSubTitle2;
113         @Nullable private String mLeftButtonText;
114         @Nullable private String mRightButtonText;
115         @Nullable private Consumer<AlertDialog> mLeftButtonOnClickListener;
116         @Nullable private Consumer<AlertDialog> mRightButtonOnClickListener;
117 
118         /**
119          * Constructs a new instance of DialogBuilder.
120          *
121          * @param context The context used for building the dialog.
122          */
DialogBuilder(Context context)123         public DialogBuilder(Context context) {
124             mContext = context;
125             mBuilder = new AlertDialog.Builder(context);
126         }
127 
128         /**
129          * Sets the title of the dialog.
130          *
131          * @param title The title text.
132          * @return This DialogBuilder instance.
133          */
setTitle(String title)134         public DialogBuilder setTitle(String title) {
135             mTitle = title;
136             return this;
137         }
138 
139         /**
140          * Sets the first subtitle of the dialog.
141          *
142          * @param subTitle1 The text of the first subtitle.
143          * @return This DialogBuilder instance.
144          */
setSubTitle1(String subTitle1)145         public DialogBuilder setSubTitle1(String subTitle1) {
146             mSubTitle1 = subTitle1;
147             return this;
148         }
149 
150         /**
151          * Sets the second subtitle of the dialog.
152          *
153          * @param subTitle2 The text of the second subtitle.
154          * @return This DialogBuilder instance.
155          */
setSubTitle2(String subTitle2)156         public DialogBuilder setSubTitle2(String subTitle2) {
157             mSubTitle2 = subTitle2;
158             return this;
159         }
160 
161         /**
162          * Sets the text of the left button.
163          *
164          * @param text The text of the left button.
165          * @return This DialogBuilder instance.
166          */
setLeftButtonText(String text)167         public DialogBuilder setLeftButtonText(String text) {
168             mLeftButtonText = text;
169             return this;
170         }
171 
172         /**
173          * Sets the click listener of the left button.
174          *
175          * @param listener The click listener for the left button.
176          * @return This DialogBuilder instance.
177          */
setLeftButtonOnClickListener(Consumer<AlertDialog> listener)178         public DialogBuilder setLeftButtonOnClickListener(Consumer<AlertDialog> listener) {
179             mLeftButtonOnClickListener = listener;
180             return this;
181         }
182 
183         /**
184          * Sets the text of the right button.
185          *
186          * @param text The text of the right button.
187          * @return This DialogBuilder instance.
188          */
setRightButtonText(String text)189         public DialogBuilder setRightButtonText(String text) {
190             mRightButtonText = text;
191             return this;
192         }
193 
194         /**
195          * Sets the click listener of the right button.
196          *
197          * @param listener The click listener for the right button.
198          * @return This DialogBuilder instance.
199          */
setRightButtonOnClickListener(Consumer<AlertDialog> listener)200         public DialogBuilder setRightButtonOnClickListener(Consumer<AlertDialog> listener) {
201             mRightButtonOnClickListener = listener;
202             return this;
203         }
204 
build()205         AlertDialog build() {
206             View rootView =
207                     LayoutInflater.from(mContext)
208                             .inflate(R.xml.bluetooth_audio_streams_dialog, /* parent= */ null);
209 
210             AlertDialog dialog = mBuilder.setView(rootView).setCancelable(false).create();
211             dialog.setCanceledOnTouchOutside(false);
212 
213             TextView title = rootView.requireViewById(R.id.dialog_title);
214             title.setText(mTitle);
215 
216             if (!Strings.isNullOrEmpty(mSubTitle1)) {
217                 TextView subTitle1 = rootView.requireViewById(R.id.dialog_subtitle);
218                 subTitle1.setText(mSubTitle1);
219                 subTitle1.setVisibility(View.VISIBLE);
220             }
221             if (!Strings.isNullOrEmpty(mSubTitle2)) {
222                 TextView subTitle2 = rootView.requireViewById(R.id.dialog_subtitle_2);
223                 subTitle2.setText(mSubTitle2);
224                 subTitle2.setVisibility(View.VISIBLE);
225             }
226             if (!Strings.isNullOrEmpty(mLeftButtonText)) {
227                 Button leftButton = rootView.requireViewById(R.id.left_button);
228                 leftButton.setText(mLeftButtonText);
229                 leftButton.setVisibility(View.VISIBLE);
230                 leftButton.setOnClickListener(
231                         unused -> {
232                             if (mLeftButtonOnClickListener != null) {
233                                 mLeftButtonOnClickListener.accept(dialog);
234                             }
235                         });
236             }
237             if (!Strings.isNullOrEmpty(mRightButtonText)) {
238                 Button rightButton = rootView.requireViewById(R.id.right_button);
239                 rightButton.setText(mRightButtonText);
240                 rightButton.setVisibility(View.VISIBLE);
241                 rightButton.setOnClickListener(
242                         unused -> {
243                             if (mRightButtonOnClickListener != null) {
244                                 mRightButtonOnClickListener.accept(dialog);
245                             }
246                         });
247             }
248 
249             return dialog;
250         }
251     }
252 }
253