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