1 /*
2  * Copyright (C) 2022 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 package com.android.adservices.ui.settings;
17 
18 import android.content.DialogInterface.OnClickListener;
19 import android.os.Build;
20 import android.widget.Toast;
21 
22 import androidx.annotation.NonNull;
23 import androidx.annotation.RequiresApi;
24 import androidx.fragment.app.FragmentActivity;
25 
26 import com.android.adservices.api.R;
27 import com.android.adservices.data.topics.Topic;
28 import com.android.adservices.service.consent.App;
29 import com.android.adservices.service.topics.TopicsMapper;
30 import com.android.adservices.ui.settings.viewmodels.AppsViewModel;
31 import com.android.adservices.ui.settings.viewmodels.MainViewModel;
32 import com.android.adservices.ui.settings.viewmodels.MeasurementViewModel;
33 import com.android.adservices.ui.settings.viewmodels.TopicsViewModel;
34 
35 import java.io.IOException;
36 
37 /**
38  * Creates and displays dialogs for the Privacy Sandbox application. This should be a substitute of
39  * DialogManager It should solve double click and dismiss when rotating
40  */
41 // TODO(b/269798827): Enable for R.
42 @RequiresApi(Build.VERSION_CODES.S)
43 public class DialogFragmentManager {
44     static boolean sIsShowing = false;
45     /**
46      * Shows the dialog for opting out of Privacy Sandbox.
47      *
48      * @param fragmentActivity {@link FragmentActivity}.
49      * @param mainViewModel {@link MainViewModel}.
50      */
showOptOutDialogFragment( @onNull FragmentActivity fragmentActivity, MainViewModel mainViewModel)51     public static void showOptOutDialogFragment(
52             @NonNull FragmentActivity fragmentActivity, MainViewModel mainViewModel) {
53         if (sIsShowing) return;
54 
55         OnClickListener positiveOnClickListener =
56                 (dialogInterface, buttonId) -> {
57                     mainViewModel.setConsent(false);
58                     sIsShowing = false;
59                 };
60 
61         SpeedBumpDialogFragment dialog =
62                 SpeedBumpDialogFragment.newInstance(
63                         fragmentActivity.getString(R.string.settingsUI_dialog_opt_out_title),
64                         fragmentActivity.getString(R.string.settingsUI_dialog_opt_out_message),
65                         fragmentActivity.getString(
66                                 R.string.settingsUI_dialog_opt_out_positive_text),
67                         fragmentActivity.getString(R.string.settingsUI_dialog_negative_text),
68                         positiveOnClickListener);
69 
70         sIsShowing = true;
71         dialog.show(fragmentActivity.getSupportFragmentManager(), "OptOutDialogFragment");
72     }
73 
74     /**
75      * Shows the dialog for blocking a topic.
76      *
77      * @param fragmentActivity {@link FragmentActivity}.
78      * @param topicsViewModel {@link TopicsViewModel}.
79      * @param topic topic to block.
80      */
showBlockTopicDialog( @onNull FragmentActivity fragmentActivity, TopicsViewModel topicsViewModel, Topic topic)81     public static void showBlockTopicDialog(
82             @NonNull FragmentActivity fragmentActivity,
83             TopicsViewModel topicsViewModel,
84             Topic topic) {
85         if (sIsShowing) return;
86         OnClickListener positiveOnClickListener =
87                 (dialogInterface, buttonId) -> {
88                     topicsViewModel.revokeTopicConsent(topic);
89                     sIsShowing = false;
90                 };
91 
92         String topicName =
93                 fragmentActivity.getString(
94                         TopicsMapper.getResourceIdByTopic(topic, fragmentActivity));
95         SpeedBumpDialogFragment dialog =
96                 SpeedBumpDialogFragment.newInstance(
97                         fragmentActivity.getString(
98                                 R.string.settingsUI_dialog_block_topic_title, topicName),
99                         fragmentActivity.getString(R.string.settingsUI_dialog_block_topic_message),
100                         fragmentActivity.getString(
101                                 R.string.settingsUI_dialog_block_topic_positive_text),
102                         fragmentActivity.getString(R.string.settingsUI_dialog_negative_text),
103                         positiveOnClickListener);
104 
105         sIsShowing = true;
106         dialog.show(fragmentActivity.getSupportFragmentManager(), "showBlockTopicDialog");
107     }
108 
109     /**
110      * Shows the dialog for unblocking a topic.
111      *
112      * @param fragmentActivity {@link FragmentActivity}.
113      * @param topic topic to unblock.
114      */
showUnblockTopicDialog( @onNull FragmentActivity fragmentActivity, Topic topic)115     public static void showUnblockTopicDialog(
116             @NonNull FragmentActivity fragmentActivity, Topic topic) {
117         if (sIsShowing) return;
118         OnClickListener positiveOnClickListener = (dialogInterface, buttonId) -> sIsShowing = false;
119         String topicName =
120                 fragmentActivity.getString(
121                         TopicsMapper.getResourceIdByTopic(topic, fragmentActivity));
122         SpeedBumpDialogFragment dialog =
123                 SpeedBumpDialogFragment.newInstance(
124                         fragmentActivity.getString(
125                                 R.string.settingsUI_dialog_unblock_topic_title, topicName),
126                         fragmentActivity.getString(
127                                 R.string.settingsUI_dialog_unblock_topic_message),
128                         fragmentActivity.getString(
129                                 R.string.settingsUI_dialog_unblock_topic_positive_text),
130                         "",
131                         positiveOnClickListener);
132 
133         sIsShowing = true;
134         dialog.show(fragmentActivity.getSupportFragmentManager(), "showUnBlockTopicDialog");
135     }
136 
137     /**
138      * Shows the dialog for resetting topics. (reset does not reset blocked topics
139      *
140      * @param fragmentActivity {@link FragmentActivity}.
141      * @param topicsViewModel {@link TopicsViewModel}.
142      */
showResetTopicDialog( @onNull FragmentActivity fragmentActivity, TopicsViewModel topicsViewModel)143     public static void showResetTopicDialog(
144             @NonNull FragmentActivity fragmentActivity, TopicsViewModel topicsViewModel) {
145         if (sIsShowing) return;
146 
147         OnClickListener resetOnCLickListener =
148                 (dialog, which) -> {
149                     topicsViewModel.resetTopics();
150                     sIsShowing = false;
151                     Toast.makeText(
152                                     fragmentActivity,
153                                     R.string.settingsUI_topics_are_reset,
154                                     Toast.LENGTH_SHORT)
155                             .show();
156                 };
157 
158         SpeedBumpDialogFragment dialog =
159                 SpeedBumpDialogFragment.newInstance(
160                         fragmentActivity.getString(R.string.settingsUI_dialog_reset_topic_title),
161                         fragmentActivity.getString(R.string.settingsUI_dialog_reset_topic_message),
162                         fragmentActivity.getString(
163                                 R.string.settingsUI_dialog_reset_topic_positive_text),
164                         fragmentActivity.getString(R.string.settingsUI_dialog_negative_text),
165                         resetOnCLickListener);
166 
167         sIsShowing = true;
168         dialog.show(fragmentActivity.getSupportFragmentManager(), "showResetTopicDialog");
169     }
170 
171     /**
172      * Shows the dialog for blocking a topic.
173      *
174      * @param fragmentActivity {@link FragmentActivity}.
175      * @param appsViewModel {@link AppsViewModel}.
176      * @param app the app {@link App} to block.
177      */
showBlockAppDialog( @onNull FragmentActivity fragmentActivity, AppsViewModel appsViewModel, App app)178     public static void showBlockAppDialog(
179             @NonNull FragmentActivity fragmentActivity, AppsViewModel appsViewModel, App app) {
180         if (sIsShowing) return;
181         OnClickListener positiveOnClickListener =
182                 (dialogInterface, buttonId) -> {
183                     try {
184                         appsViewModel.revokeAppConsent(app);
185                     } catch (IOException e) {
186                         e.printStackTrace();
187                     }
188                     sIsShowing = false;
189                 };
190 
191         String appName = app.getAppDisplayName(fragmentActivity.getPackageManager());
192         SpeedBumpDialogFragment dialog =
193                 SpeedBumpDialogFragment.newInstance(
194                         fragmentActivity.getString(
195                                 R.string.settingsUI_dialog_block_app_title, appName),
196                         fragmentActivity.getString(R.string.settingsUI_dialog_block_app_message),
197                         fragmentActivity.getString(
198                                 R.string.settingsUI_dialog_block_app_positive_text),
199                         fragmentActivity.getString(R.string.settingsUI_dialog_negative_text),
200                         positiveOnClickListener);
201 
202         sIsShowing = true;
203         dialog.show(fragmentActivity.getSupportFragmentManager(), "showBlockAppDialog");
204     }
205 
206     /**
207      * Shows the dialog for unblocking a app.
208      *
209      * @param fragmentActivity {@link FragmentActivity}.
210      * @param app app {@link App} to unblock.
211      */
showUnblockAppDialog(@onNull FragmentActivity fragmentActivity, App app)212     public static void showUnblockAppDialog(@NonNull FragmentActivity fragmentActivity, App app) {
213         if (sIsShowing) return;
214         OnClickListener positiveOnClickListener = (dialogInterface, buttonId) -> sIsShowing = false;
215         String appName = app.getAppDisplayName(fragmentActivity.getPackageManager());
216         SpeedBumpDialogFragment dialog =
217                 SpeedBumpDialogFragment.newInstance(
218                         fragmentActivity.getString(
219                                 R.string.settingsUI_dialog_unblock_app_title, appName),
220                         fragmentActivity.getString(R.string.settingsUI_dialog_unblock_app_message),
221                         fragmentActivity.getString(
222                                 R.string.settingsUI_dialog_unblock_app_positive_text),
223                         "",
224                         positiveOnClickListener);
225 
226         sIsShowing = true;
227         dialog.show(fragmentActivity.getSupportFragmentManager(), "showUnBlockAppDialog");
228     }
229 
230     /**
231      * Shows the dialog for resetting apps. (reset does not reset blocked apps
232      *
233      * @param fragmentActivity {@link FragmentActivity}.
234      * @param appsViewModel {@link AppsViewModel}.
235      */
showResetAppDialog( @onNull FragmentActivity fragmentActivity, AppsViewModel appsViewModel)236     public static void showResetAppDialog(
237             @NonNull FragmentActivity fragmentActivity, AppsViewModel appsViewModel) {
238         if (sIsShowing) return;
239 
240         OnClickListener resetOnCLickListener =
241                 (dialog, which) -> {
242                     try {
243                         appsViewModel.resetApps();
244                         sIsShowing = false;
245                         Toast.makeText(
246                                         fragmentActivity,
247                                         R.string.settingsUI_apps_are_reset,
248                                         Toast.LENGTH_SHORT)
249                                 .show();
250                     } catch (IOException ioException) {
251                         ioException.printStackTrace();
252                     }
253 
254                     sIsShowing = false;
255                 };
256 
257         SpeedBumpDialogFragment dialog =
258                 SpeedBumpDialogFragment.newInstance(
259                         fragmentActivity.getString(R.string.settingsUI_dialog_reset_app_title),
260                         fragmentActivity.getString(R.string.settingsUI_dialog_reset_app_message),
261                         fragmentActivity.getString(
262                                 R.string.settingsUI_dialog_reset_app_positive_text),
263                         fragmentActivity.getString(R.string.settingsUI_dialog_negative_text),
264                         resetOnCLickListener);
265 
266         sIsShowing = true;
267         dialog.show(fragmentActivity.getSupportFragmentManager(), "showResetAppDialog");
268     }
269 
270     /**
271      * Shows the speed-bump dialog for turn on the switch of Topics
272      *
273      * @param fragmentActivity {@link FragmentActivity}.
274      */
showOptInTopicsDialog(@onNull FragmentActivity fragmentActivity)275     public static void showOptInTopicsDialog(@NonNull FragmentActivity fragmentActivity) {
276         if (sIsShowing) return;
277         OnClickListener acknowledgeListener = (dialogInterface, buttonId) -> sIsShowing = false;
278 
279         SpeedBumpDialogFragment dialog =
280                 SpeedBumpDialogFragment.newInstance(
281                         fragmentActivity.getString(R.string.settingsUI_dialog_topics_opt_in_title),
282                         fragmentActivity.getString(
283                                 R.string.settingsUI_dialog_topics_opt_in_message),
284                         fragmentActivity.getString(R.string.settingsUI_dialog_acknowledge),
285                         "",
286                         acknowledgeListener);
287 
288         sIsShowing = true;
289         dialog.show(fragmentActivity.getSupportFragmentManager(), "OptInTopicsDialogFragment");
290     }
291 
292     /**
293      * Shows the speed-bump dialog of turning off topics.
294      *
295      * @param fragmentActivity {@link FragmentActivity}.
296      * @param topicsViewModel {@link TopicsViewModel}.
297      */
showOptOutTopicsDialog( @onNull FragmentActivity fragmentActivity, TopicsViewModel topicsViewModel)298     public static void showOptOutTopicsDialog(
299             @NonNull FragmentActivity fragmentActivity, TopicsViewModel topicsViewModel) {
300         if (sIsShowing) return;
301         OnClickListener optOutTopicsListener =
302                 (dialogInterface, buttonId) -> {
303                     topicsViewModel.setTopicsConsent(false);
304                     topicsViewModel.refresh();
305                     sIsShowing = false;
306                 };
307 
308         SpeedBumpDialogFragment dialog =
309                 SpeedBumpDialogFragment.newInstance(
310                         fragmentActivity.getString(R.string.settingsUI_dialog_topics_opt_out_title),
311                         fragmentActivity.getString(
312                                 R.string.settingsUI_dialog_topics_opt_out_message),
313                         fragmentActivity.getString(
314                                 R.string.settingsUI_dialog_opt_out_positive_text),
315                         fragmentActivity.getString(R.string.settingsUI_dialog_negative_text),
316                         optOutTopicsListener);
317 
318         sIsShowing = true;
319         dialog.show(fragmentActivity.getSupportFragmentManager(), "OptOutTopicsDialogFragment");
320     }
321 
322     /**
323      * Shows the speed-bump dialog for turn on the switch of apps
324      *
325      * @param fragmentActivity {@link FragmentActivity}.
326      */
showOptInAppsDialog(@onNull FragmentActivity fragmentActivity)327     public static void showOptInAppsDialog(@NonNull FragmentActivity fragmentActivity) {
328         if (sIsShowing) return;
329         OnClickListener acknowledgeListener = (dialogInterface, buttonId) -> sIsShowing = false;
330 
331         SpeedBumpDialogFragment dialog =
332                 SpeedBumpDialogFragment.newInstance(
333                         fragmentActivity.getString(R.string.settingsUI_dialog_apps_opt_in_title),
334                         fragmentActivity.getString(R.string.settingsUI_dialog_apps_opt_in_message),
335                         fragmentActivity.getString(R.string.settingsUI_dialog_acknowledge),
336                         "",
337                         acknowledgeListener);
338 
339         sIsShowing = true;
340         dialog.show(fragmentActivity.getSupportFragmentManager(), "OptInAppsDialogFragment");
341     }
342 
343     /**
344      * Shows the speed-bump dialog of turning off apps.
345      *
346      * @param fragmentActivity {@link FragmentActivity}.
347      * @param appsViewModel {@link AppsViewModel}.
348      */
showOptOutAppsDialog( @onNull FragmentActivity fragmentActivity, AppsViewModel appsViewModel)349     public static void showOptOutAppsDialog(
350             @NonNull FragmentActivity fragmentActivity, AppsViewModel appsViewModel) {
351         if (sIsShowing) return;
352         OnClickListener optOutAppsListener =
353                 (dialogInterface, buttonId) -> {
354                     appsViewModel.setAppsConsent(false);
355                     appsViewModel.refresh();
356                     sIsShowing = false;
357                 };
358 
359         SpeedBumpDialogFragment dialog =
360                 SpeedBumpDialogFragment.newInstance(
361                         fragmentActivity.getString(R.string.settingsUI_dialog_apps_opt_out_title),
362                         fragmentActivity.getString(R.string.settingsUI_dialog_apps_opt_out_message),
363                         fragmentActivity.getString(
364                                 R.string.settingsUI_dialog_opt_out_positive_text),
365                         fragmentActivity.getString(R.string.settingsUI_dialog_negative_text),
366                         optOutAppsListener);
367 
368         sIsShowing = true;
369         dialog.show(fragmentActivity.getSupportFragmentManager(), "OptOutAppsDialogFragment");
370     }
371 
372     /**
373      * Shows the speed-bump dialog for turn on the switch of measurement
374      *
375      * @param fragmentActivity {@link FragmentActivity}.
376      */
showOptInMeasurementDialog(@onNull FragmentActivity fragmentActivity)377     public static void showOptInMeasurementDialog(@NonNull FragmentActivity fragmentActivity) {
378         if (sIsShowing) return;
379         OnClickListener acknowledgeListener = (dialogInterface, buttonId) -> sIsShowing = false;
380 
381         SpeedBumpDialogFragment dialog =
382                 SpeedBumpDialogFragment.newInstance(
383                         fragmentActivity.getString(
384                                 R.string.settingsUI_dialog_measurement_opt_in_title),
385                         fragmentActivity.getString(
386                                 R.string.settingsUI_dialog_measurement_opt_in_message),
387                         fragmentActivity.getString(R.string.settingsUI_dialog_acknowledge),
388                         "",
389                         acknowledgeListener);
390 
391         sIsShowing = true;
392         dialog.show(fragmentActivity.getSupportFragmentManager(), "OptInMeasurementDialogFragment");
393     }
394 
395     /**
396      * Shows the speed-bump dialog of turning off measurement.
397      *
398      * @param fragmentActivity {@link FragmentActivity}.
399      * @param measurementViewModel {@link MeasurementViewModel}.
400      */
showOptOutMeasurementDialog( @onNull FragmentActivity fragmentActivity, MeasurementViewModel measurementViewModel)401     public static void showOptOutMeasurementDialog(
402             @NonNull FragmentActivity fragmentActivity, MeasurementViewModel measurementViewModel) {
403         if (sIsShowing) return;
404         OnClickListener optOutMeasurementListener =
405                 (dialogInterface, buttonId) -> {
406                     measurementViewModel.setMeasurementConsent(false);
407                     sIsShowing = false;
408                 };
409 
410         SpeedBumpDialogFragment dialog =
411                 SpeedBumpDialogFragment.newInstance(
412                         fragmentActivity.getString(
413                                 R.string.settingsUI_dialog_measurement_opt_out_title),
414                         fragmentActivity.getString(
415                                 R.string.settingsUI_dialog_measurement_opt_out_message),
416                         fragmentActivity.getString(
417                                 R.string.settingsUI_dialog_opt_out_positive_text),
418                         fragmentActivity.getString(R.string.settingsUI_dialog_negative_text),
419                         optOutMeasurementListener);
420 
421         sIsShowing = true;
422         dialog.show(
423                 fragmentActivity.getSupportFragmentManager(), "OptOutMeasurementDialogFragment");
424     }
425 }
426