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.delegates; 17 18 import android.content.Intent; 19 import android.os.Build; 20 import android.text.method.LinkMovementMethod; 21 import android.util.Log; 22 import android.util.Pair; 23 import android.view.View; 24 import android.widget.TextView; 25 26 import androidx.annotation.RequiresApi; 27 import androidx.lifecycle.Observer; 28 29 import com.android.adservices.api.R; 30 import com.android.adservices.service.FlagsFactory; 31 import com.android.adservices.service.consent.App; 32 import com.android.adservices.service.stats.UiStatsLogger; 33 import com.android.adservices.ui.settings.DialogFragmentManager; 34 import com.android.adservices.ui.settings.DialogManager; 35 import com.android.adservices.ui.settings.activities.AppsActivity; 36 import com.android.adservices.ui.settings.activities.BlockedAppsActivity; 37 import com.android.adservices.ui.settings.fragments.AdServicesSettingsAppsFragment; 38 import com.android.adservices.ui.settings.viewmodels.AppsViewModel; 39 import com.android.adservices.ui.settings.viewmodels.AppsViewModel.AppsViewModelUiEvent; 40 import com.android.settingslib.widget.MainSwitchBar; 41 42 import java.io.IOException; 43 44 /** 45 * Delegate class that helps AdServices Settings fragments to respond to all view model/user events. 46 */ 47 @RequiresApi(Build.VERSION_CODES.S) 48 public class AppsActionDelegate { 49 private final AppsActivity mAppsActivity; 50 private final AppsViewModel mAppsViewModel; 51 AppsActionDelegate(AppsActivity appsActivity, AppsViewModel appsViewModel)52 public AppsActionDelegate(AppsActivity appsActivity, AppsViewModel appsViewModel) { 53 mAppsActivity = appsActivity; 54 mAppsViewModel = appsViewModel; 55 listenToAppsViewModelUiEvents(); 56 } 57 listenToAppsViewModelUiEvents()58 private void listenToAppsViewModelUiEvents() { 59 Observer<Pair<AppsViewModelUiEvent, App>> observer = 60 eventAppPair -> { 61 if (eventAppPair == null) { 62 return; 63 } 64 AppsViewModelUiEvent event = eventAppPair.first; 65 App app = eventAppPair.second; 66 if (event == null) { 67 return; 68 } 69 try { 70 switch (event) { 71 case SWITCH_ON_APPS: 72 if (FlagsFactory.getFlags().getToggleSpeedBumpEnabled()) { 73 DialogFragmentManager.showOptInAppsDialog(mAppsActivity); 74 } 75 mAppsViewModel.setAppsConsent(true); 76 mAppsViewModel.refresh(); 77 break; 78 case SWITCH_OFF_APPS: 79 if (FlagsFactory.getFlags().getToggleSpeedBumpEnabled()) { 80 DialogFragmentManager.showOptOutAppsDialog( 81 mAppsActivity, mAppsViewModel); 82 } else { 83 mAppsViewModel.setAppsConsent(false); 84 mAppsViewModel.refresh(); 85 } 86 87 break; 88 case BLOCK_APP: 89 UiStatsLogger.logBlockAppSelected(); 90 if (FlagsFactory.getFlags().getUiDialogsFeatureEnabled()) { 91 if (FlagsFactory.getFlags().getUiDialogFragmentEnabled()) { 92 DialogFragmentManager.showBlockAppDialog( 93 mAppsActivity, mAppsViewModel, app); 94 } else { 95 DialogManager.showBlockAppDialog( 96 mAppsActivity, mAppsViewModel, app); 97 } 98 } else { 99 mAppsViewModel.revokeAppConsent(app); 100 } 101 break; 102 case RESET_APPS: 103 UiStatsLogger.logResetAppSelected(); 104 if (FlagsFactory.getFlags().getUiDialogsFeatureEnabled()) { 105 if (FlagsFactory.getFlags().getUiDialogFragmentEnabled()) { 106 DialogFragmentManager.showResetAppDialog( 107 mAppsActivity, mAppsViewModel); 108 } else { 109 DialogManager.showResetAppDialog( 110 mAppsActivity, mAppsViewModel); 111 } 112 } else { 113 mAppsViewModel.resetApps(); 114 } 115 break; 116 case DISPLAY_BLOCKED_APPS_FRAGMENT: 117 Intent intent = 118 new Intent(mAppsActivity, BlockedAppsActivity.class); 119 mAppsActivity.startActivity(intent); 120 break; 121 default: 122 Log.e("AdservicesUI", "Unknown Action for UI Logging"); 123 } 124 } catch (IOException e) { 125 Log.e( 126 "AdServicesUI", 127 "Error while processing AppsViewModelUiEvent " + event + ":" + e); 128 } finally { 129 mAppsViewModel.uiEventHandled(); 130 } 131 }; 132 mAppsViewModel.getUiEvents().observe(mAppsActivity, observer); 133 } 134 135 /** 136 * Configure all UI elements (except apps list) in {@link AdServicesSettingsAppsFragment} to 137 * handle user actions. 138 */ initAppsFragment(AdServicesSettingsAppsFragment fragment)139 public void initAppsFragment(AdServicesSettingsAppsFragment fragment) { 140 mAppsActivity.setTitle(R.string.settingsUI_apps_ga_title); 141 142 configureAppsConsentSwitch(fragment); 143 144 setGaUxAppsViewText(); 145 configureBlockedAppsFragmentButton(fragment); 146 configureResetAppsButton(fragment); 147 } 148 setGaUxAppsViewText()149 private void setGaUxAppsViewText() { 150 ((TextView) mAppsActivity.findViewById(R.id.reset_apps_button_child)) 151 .setText(R.string.settingsUI_reset_apps_ga_title); 152 ((TextView) mAppsActivity.findViewById(R.id.no_apps_state)) 153 .setText(R.string.settingsUI_apps_view_no_apps_ga_text); 154 ((TextView) mAppsActivity.findViewById(R.id.no_apps_state)) 155 .setMovementMethod(LinkMovementMethod.getInstance()); 156 } 157 configureAppsConsentSwitch(AdServicesSettingsAppsFragment fragment)158 private void configureAppsConsentSwitch(AdServicesSettingsAppsFragment fragment) { 159 MainSwitchBar appsSwitchBar = mAppsActivity.findViewById(R.id.apps_switch_bar); 160 161 mAppsViewModel.getAppsConsent().observe(fragment, appsSwitchBar::setChecked); 162 appsSwitchBar.setOnClickListener( 163 switchBar -> mAppsViewModel.consentSwitchClickHandler((MainSwitchBar) switchBar)); 164 } 165 configureBlockedAppsFragmentButton(AdServicesSettingsAppsFragment fragment)166 private void configureBlockedAppsFragmentButton(AdServicesSettingsAppsFragment fragment) { 167 View blockedAppsButton = fragment.requireView().findViewById(R.id.blocked_apps_button); 168 View blockedAppsWhenEmptyListButton = 169 fragment.requireView().findViewById(R.id.blocked_apps_when_empty_state_button); 170 171 blockedAppsButton.setOnClickListener( 172 view -> { 173 mAppsViewModel.blockedAppsFragmentButtonClickHandler(); 174 }); 175 blockedAppsWhenEmptyListButton.setOnClickListener( 176 view -> { 177 mAppsViewModel.blockedAppsFragmentButtonClickHandler(); 178 }); 179 } 180 configureResetAppsButton(AdServicesSettingsAppsFragment fragment)181 private void configureResetAppsButton(AdServicesSettingsAppsFragment fragment) { 182 View resetAppsButton = fragment.requireView().findViewById(R.id.reset_apps_button); 183 184 resetAppsButton.setOnClickListener(view -> mAppsViewModel.resetAppsButtonClickHandler()); 185 } 186 } 187