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.Pair;
22 import android.view.View;
23 import android.widget.TextView;
24 
25 import androidx.annotation.RequiresApi;
26 import androidx.lifecycle.Observer;
27 
28 import com.android.adservices.api.R;
29 import com.android.adservices.data.topics.Topic;
30 import com.android.adservices.service.FlagsFactory;
31 import com.android.adservices.service.stats.UiStatsLogger;
32 import com.android.adservices.ui.settings.DialogFragmentManager;
33 import com.android.adservices.ui.settings.DialogManager;
34 import com.android.adservices.ui.settings.activities.BlockedTopicsActivity;
35 import com.android.adservices.ui.settings.activities.TopicsActivity;
36 import com.android.adservices.ui.settings.fragments.AdServicesSettingsTopicsFragment;
37 import com.android.adservices.ui.settings.viewmodels.TopicsViewModel;
38 import com.android.adservices.ui.settings.viewmodels.TopicsViewModel.TopicsViewModelUiEvent;
39 import com.android.settingslib.widget.MainSwitchBar;
40 
41 /**
42  * Delegate class that helps AdServices Settings fragments to respond to all view model/user events.
43  */
44 @RequiresApi(Build.VERSION_CODES.S)
45 public class TopicsActionDelegate {
46     private final TopicsActivity mTopicsActivity;
47     private final TopicsViewModel mTopicsViewModel;
48 
TopicsActionDelegate(TopicsActivity topicsActivity, TopicsViewModel topicsViewModel)49     public TopicsActionDelegate(TopicsActivity topicsActivity, TopicsViewModel topicsViewModel) {
50         mTopicsActivity = topicsActivity;
51         mTopicsViewModel = topicsViewModel;
52         listenToTopicsViewModelUiEvents();
53     }
54 
listenToTopicsViewModelUiEvents()55     private void listenToTopicsViewModelUiEvents() {
56         Observer<Pair<TopicsViewModelUiEvent, Topic>> observer =
57                 eventTopicPair -> {
58                     if (eventTopicPair == null) {
59                         return;
60                     }
61                     TopicsViewModelUiEvent event = eventTopicPair.first;
62                     Topic topic = eventTopicPair.second;
63                     if (event == null) {
64                         return;
65                     }
66                     try {
67                         switch (event) {
68                             case SWITCH_ON_TOPICS:
69                                 if (FlagsFactory.getFlags().getToggleSpeedBumpEnabled()) {
70                                     DialogFragmentManager.showOptInTopicsDialog(mTopicsActivity);
71                                 }
72                                 mTopicsViewModel.setTopicsConsent(true);
73                                 mTopicsViewModel.refresh();
74                                 break;
75                             case SWITCH_OFF_TOPICS:
76                                 if (FlagsFactory.getFlags().getToggleSpeedBumpEnabled()) {
77                                     DialogFragmentManager.showOptOutTopicsDialog(
78                                             mTopicsActivity, mTopicsViewModel);
79                                 } else {
80                                     mTopicsViewModel.setTopicsConsent(false);
81                                     mTopicsViewModel.refresh();
82                                 }
83                                 break;
84                             case BLOCK_TOPIC:
85                                 UiStatsLogger.logBlockTopicSelected();
86                                 if (FlagsFactory.getFlags().getUiDialogsFeatureEnabled()) {
87                                     if (FlagsFactory.getFlags().getUiDialogFragmentEnabled()) {
88                                         DialogFragmentManager.showBlockTopicDialog(
89                                                 mTopicsActivity, mTopicsViewModel, topic);
90                                     } else {
91                                         DialogManager.showBlockTopicDialog(
92                                                 mTopicsActivity, mTopicsViewModel, topic);
93                                     }
94                                 } else {
95                                     mTopicsViewModel.revokeTopicConsent(topic);
96                                 }
97                                 break;
98                             case RESET_TOPICS:
99                                 UiStatsLogger.logResetTopicSelected();
100                                 if (FlagsFactory.getFlags().getUiDialogsFeatureEnabled()) {
101                                     if (FlagsFactory.getFlags().getUiDialogFragmentEnabled()) {
102                                         DialogFragmentManager.showResetTopicDialog(
103                                                 mTopicsActivity, mTopicsViewModel);
104                                     } else {
105                                         DialogManager.showResetTopicDialog(
106                                                 mTopicsActivity, mTopicsViewModel);
107                                     }
108                                 } else {
109                                     mTopicsViewModel.resetTopics();
110                                 }
111                                 break;
112                             case DISPLAY_BLOCKED_TOPICS_FRAGMENT:
113                                 Intent intent =
114                                         new Intent(mTopicsActivity, BlockedTopicsActivity.class);
115                                 mTopicsActivity.startActivity(intent);
116                                 break;
117                         }
118                     } finally {
119                         mTopicsViewModel.uiEventHandled();
120                     }
121                 };
122         mTopicsViewModel.getUiEvents().observe(mTopicsActivity, observer);
123     }
124 
125     /**
126      * Configure all UI elements (except topics list) in {@link AdServicesSettingsTopicsFragment} to
127      * handle user actions.
128      */
initTopicsFragment(AdServicesSettingsTopicsFragment fragment)129     public void initTopicsFragment(AdServicesSettingsTopicsFragment fragment) {
130         mTopicsActivity.setTitle(R.string.settingsUI_topics_ga_title);
131 
132         configureTopicsConsentSwitch(fragment);
133 
134         setGaUxTopicsViewText();
135         configureBlockedTopicsFragmentButton(fragment);
136         configureResetTopicsButton(fragment);
137     }
138 
setGaUxTopicsViewText()139     private void setGaUxTopicsViewText() {
140         ((TextView) mTopicsActivity.findViewById(R.id.blocked_topics_button_child))
141                 .setText(R.string.settingsUI_blocked_topics_ga_title);
142         ((TextView) mTopicsActivity.findViewById(R.id.reset_topics_button_child))
143                 .setText(R.string.settingsUI_reset_topics_ga_title);
144         ((TextView) mTopicsActivity.findViewById(R.id.no_topics_state))
145                 .setText(R.string.settingsUI_topics_view_no_topics_ga_text);
146         ((TextView) mTopicsActivity.findViewById(R.id.no_topics_state))
147                 .setMovementMethod(LinkMovementMethod.getInstance());
148     }
149 
configureTopicsConsentSwitch(AdServicesSettingsTopicsFragment fragment)150     private void configureTopicsConsentSwitch(AdServicesSettingsTopicsFragment fragment) {
151         MainSwitchBar topicsSwitchBar = mTopicsActivity.findViewById(R.id.topics_switch_bar);
152 
153         mTopicsViewModel.getTopicsConsent().observe(fragment, topicsSwitchBar::setChecked);
154         topicsSwitchBar.setOnClickListener(
155                 switchBar -> mTopicsViewModel.consentSwitchClickHandler((MainSwitchBar) switchBar));
156     }
157 
configureBlockedTopicsFragmentButton(AdServicesSettingsTopicsFragment fragment)158     private void configureBlockedTopicsFragmentButton(AdServicesSettingsTopicsFragment fragment) {
159         View blockedTopicsButton = fragment.requireView().findViewById(R.id.blocked_topics_button);
160         View blockedTopicsWhenEmptyListButton =
161                 fragment.requireView().findViewById(R.id.blocked_topics_when_empty_state_button);
162         blockedTopicsButton.setOnClickListener(
163                 view -> mTopicsViewModel.blockedTopicsFragmentButtonClickHandler());
164         blockedTopicsWhenEmptyListButton.setOnClickListener(
165                 view -> mTopicsViewModel.blockedTopicsFragmentButtonClickHandler());
166     }
167 
configureResetTopicsButton(AdServicesSettingsTopicsFragment fragment)168     private void configureResetTopicsButton(AdServicesSettingsTopicsFragment fragment) {
169         View resetTopicsButton = fragment.requireView().findViewById(R.id.reset_topics_button);
170         resetTopicsButton.setOnClickListener(
171                 view -> mTopicsViewModel.resetTopicsButtonClickHandler());
172     }
173 }
174