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