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.fragments;
17 
18 import android.os.Build;
19 import android.os.Bundle;
20 import android.view.LayoutInflater;
21 import android.view.View;
22 import android.view.ViewGroup;
23 import android.widget.Button;
24 
25 import androidx.annotation.NonNull;
26 import androidx.annotation.RequiresApi;
27 import androidx.fragment.app.Fragment;
28 import androidx.lifecycle.ViewModelProvider;
29 import androidx.recyclerview.widget.LinearLayoutManager;
30 import androidx.recyclerview.widget.RecyclerView;
31 
32 import com.android.adservices.api.R;
33 import com.android.adservices.data.topics.Topic;
34 import com.android.adservices.service.FlagsFactory;
35 import com.android.adservices.ui.settings.activities.TopicsActivity;
36 import com.android.adservices.ui.settings.delegates.TopicsActionDelegate;
37 import com.android.adservices.ui.settings.viewadatpors.TopicsListViewAdapter;
38 import com.android.adservices.ui.settings.viewmodels.TopicsViewModel;
39 
40 import java.util.function.Function;
41 
42 /** Fragment for the topics view of the AdServices Settings App. */
43 @RequiresApi(Build.VERSION_CODES.S)
44 public class AdServicesSettingsTopicsFragment extends Fragment {
45 
46     @Override
onCreateView( LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)47     public View onCreateView(
48             LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
49         return inflater.inflate(R.layout.topics_fragment, container, false);
50     }
51 
52     @Override
onViewCreated(@onNull View view, Bundle savedInstanceState)53     public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
54         setupViewModel(view);
55     }
56 
57     @Override
onResume()58     public void onResume() {
59         super.onResume();
60         TopicsViewModel viewModel =
61                 new ViewModelProvider(requireActivity()).get(TopicsViewModel.class);
62         viewModel.refresh();
63         initActionListeners();
64     }
65 
66     // initialize all action listeners except for actions in topics list
initActionListeners()67     private void initActionListeners() {
68         TopicsActionDelegate actionDelegate =
69                 ((TopicsActivity) requireActivity()).getActionDelegate();
70         actionDelegate.initTopicsFragment(this);
71     }
72 
73     // initializes view model connection with topics list.
74     // (Action listeners for each item in the list will be handled by the adapter)
setupViewModel(View rootView)75     private void setupViewModel(View rootView) {
76         // create adapter
77         TopicsViewModel viewModel =
78                 new ViewModelProvider(requireActivity()).get(TopicsViewModel.class);
79         Function<Topic, View.OnClickListener> getOnclickListener =
80                 topic -> view -> viewModel.revokeTopicConsentButtonClickHandler(topic);
81         TopicsListViewAdapter adapter =
82                 new TopicsListViewAdapter(
83                         requireContext(), viewModel.getTopics(), getOnclickListener, false);
84 
85         // set adapter for recyclerView
86         RecyclerView recyclerView = rootView.findViewById(R.id.topics_list);
87         recyclerView.setLayoutManager(new LinearLayoutManager(requireContext()));
88         recyclerView.setAdapter(adapter);
89 
90         View noTopicsMessage = rootView.findViewById(R.id.no_topics_message);
91         View emptyTopicsHiddenSection = rootView.findViewById(R.id.empty_topics_hidden_section);
92         View blockedTopicsButton = rootView.findViewById(R.id.blocked_topics_button);
93 
94         // "Empty State": the state when the non-blocked list of apps/topics is empty.
95         // blocked_apps_when_empty_state_button is added to noTopicsMessage
96         // noTopicsMessages is visible only when Empty State
97         // blocked_topics_when_empty_state_button differs from blocked_topics_button
98         // in style with rounded corners, centered, colored
99         viewModel
100                 .getTopics()
101                 .observe(
102                         getViewLifecycleOwner(),
103                         topicsList -> {
104                             if (topicsList.isEmpty()) {
105                                 noTopicsMessage.setVisibility(View.VISIBLE);
106                                 emptyTopicsHiddenSection.setVisibility(View.GONE);
107                                 blockedTopicsButton.setVisibility(View.GONE);
108                             } else {
109                                 noTopicsMessage.setVisibility(View.GONE);
110                                 emptyTopicsHiddenSection.setVisibility(View.VISIBLE);
111                                 blockedTopicsButton.setVisibility(View.VISIBLE);
112                             }
113                             adapter.notifyDataSetChanged();
114                         });
115 
116         // locked_topics_when_empty_state_button is disabled if there is no blocked topics
117         Button blockedTopicsEmptyStateButton =
118                 rootView.findViewById(R.id.blocked_topics_when_empty_state_button);
119         viewModel
120                 .getBlockedTopics()
121                 .observe(
122                         getViewLifecycleOwner(),
123                         blockedTopicsList -> {
124                             boolean ga = FlagsFactory.getFlags().getGaUxFeatureEnabled();
125                             if (blockedTopicsList.isEmpty()) {
126                                 blockedTopicsEmptyStateButton.setEnabled(false);
127                                 blockedTopicsEmptyStateButton.setAlpha(
128                                         getResources().getFloat(R.dimen.disabled_button_alpha));
129                                 if (ga) {
130                                     blockedTopicsEmptyStateButton.setText(
131                                             R.string.settingsUI_no_blocked_topics_ga_text);
132                                 } else {
133                                     blockedTopicsEmptyStateButton.setText(
134                                             R.string.settingsUI_topics_view_no_blocked_topics_text);
135                                 }
136 
137                             } else {
138                                 blockedTopicsEmptyStateButton.setEnabled(true);
139                                 blockedTopicsEmptyStateButton.setAlpha(
140                                         getResources().getFloat(R.dimen.enabled_button_alpha));
141                                 blockedTopicsEmptyStateButton.setText(
142                                         ga
143                                                 ? R.string.settingsUI_view_blocked_topics_title
144                                                 : R.string.settingsUI_blocked_topics_title);
145                             }
146                         });
147     }
148 }
149