1 /*
2  * Copyright 2016, 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.managedprovisioning.preprovisioning.terms.adapters;
17 
18 import static android.view.View.TEXT_ALIGNMENT_TEXT_START;
19 
20 import static java.util.Objects.requireNonNull;
21 
22 import android.content.Context;
23 import android.content.Intent;
24 import android.view.LayoutInflater;
25 import android.view.View;
26 import android.view.ViewGroup;
27 import android.widget.ImageView;
28 import android.widget.LinearLayout;
29 import android.widget.TextView;
30 
31 import androidx.recyclerview.widget.RecyclerView;
32 
33 import com.android.managedprovisioning.R;
34 import com.android.managedprovisioning.common.AccessibilityContextMenuMaker;
35 import com.android.managedprovisioning.common.ClickableSpanFactory;
36 import com.android.managedprovisioning.common.StylerHelper;
37 import com.android.managedprovisioning.common.Utils;
38 import com.android.managedprovisioning.preprovisioning.terms.TermsDocument;
39 
40 import com.google.android.setupdesign.util.DescriptionStyler;
41 
42 import java.util.List;
43 
44 /**
45  * Displays {@link TermsDocument} objects in a {@link RecyclerView}.
46  */
47 public class TermsListAdapter extends RecyclerView.Adapter<TermsListAdapter.TermsViewHolder> {
48     private static final int VIEW_TYPE_GENERAL_DISCLAIMER = 1;
49     private static final int VIEW_TYPE_REGULAR_DISCLAIMER = 2;
50 
51     private final TermsDocument mGenericDisclaimer;
52     private final List<TermsDocument> mTermsDocuments;
53     private final LayoutInflater mInflater;
54     private final AccessibilityContextMenuMaker mContextMenuMaker;
55     private final Context mContext;
56     private final TermsBridge mTermsBridge;
57     private final Utils mUtils;
58     private final StylerHelper mStylerHelper;
59 
TermsListAdapter(Context context, TermsDocument genericDisclaimer, List<TermsDocument> termsDocuments, LayoutInflater layoutInflater, AccessibilityContextMenuMaker contextMenuMaker, TermsBridge termsBridge, Utils utils, StylerHelper stylerHelper)60     public TermsListAdapter(Context context, TermsDocument genericDisclaimer,
61             List<TermsDocument> termsDocuments, LayoutInflater layoutInflater,
62             AccessibilityContextMenuMaker contextMenuMaker, TermsBridge termsBridge, Utils utils,
63             StylerHelper stylerHelper) {
64         mGenericDisclaimer = requireNonNull(genericDisclaimer);
65         mTermsDocuments = requireNonNull(termsDocuments);
66         mInflater = requireNonNull(layoutInflater);
67         mContextMenuMaker = requireNonNull(contextMenuMaker);
68         mContext = requireNonNull(context);
69         mTermsBridge = requireNonNull(termsBridge);
70         mUtils = requireNonNull(utils);
71         mStylerHelper = requireNonNull(stylerHelper);
72     }
73 
74     @Override
onCreateViewHolder(ViewGroup parent, int viewType)75     public TermsViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
76         View rootView = null;
77         switch (viewType) {
78             case VIEW_TYPE_GENERAL_DISCLAIMER:
79                 rootView = createGeneralDisclaimerView(parent);
80                 break;
81             case VIEW_TYPE_REGULAR_DISCLAIMER:
82                 rootView = createRegularDisclaimerView(parent);
83                 break;
84         }
85         return new TermsViewHolder(rootView);
86     }
87 
createRegularDisclaimerView(ViewGroup parent)88     private View createRegularDisclaimerView(ViewGroup parent) {
89         View rootView = mInflater.inflate(
90                 R.layout.terms_disclaimer_header, parent, /* attachToRoot= */ false);
91         mStylerHelper.applyListItemStyling(rootView,
92                 new LinearLayout.LayoutParams(rootView.getLayoutParams()));
93         return rootView;
94     }
95 
createGeneralDisclaimerView(ViewGroup parent)96     private View createGeneralDisclaimerView(ViewGroup parent) {
97         View rootView = mInflater.inflate(
98                 R.layout.terms_disclaimer_general, parent, /* attachToRoot= */ false);
99         TextView textView = rootView.findViewById(R.id.terms_disclaimer_general);
100         DescriptionStyler.applyPartnerCustomizationHeavyStyle(textView);
101         textView.setTextAlignment(TEXT_ALIGNMENT_TEXT_START);
102         return rootView;
103     }
104 
105     @Override
onBindViewHolder(TermsViewHolder holder, int position)106     public void onBindViewHolder(TermsViewHolder holder, int position) {
107         int itemViewType = getItemViewType(position);
108         switch (itemViewType) {
109             case VIEW_TYPE_GENERAL_DISCLAIMER:
110                 onBindGeneralDisclaimerViewHolder(holder);
111                 break;
112             case VIEW_TYPE_REGULAR_DISCLAIMER:
113                 onBindDisclaimerViewHolder(holder, /* disclaimerIndex= */ position - 1);
114                 break;
115         }
116     }
117 
onBindGeneralDisclaimerViewHolder(TermsViewHolder holder)118     private void onBindGeneralDisclaimerViewHolder(TermsViewHolder holder) {
119         holder.mGeneralDisclaimer.setText(mGenericDisclaimer.getContent());
120     }
121 
onBindDisclaimerViewHolder(TermsViewHolder holder, int disclaimerIndex)122     private void onBindDisclaimerViewHolder(TermsViewHolder holder, int disclaimerIndex) {
123         TermsDocument disclaimer = getDisclaimer(disclaimerIndex);
124         String heading = disclaimer.getHeading();
125         setupRootView(disclaimerIndex, heading, holder);
126         setupDisclaimerHeading(heading, holder);
127         setupDisclaimerContent(disclaimer, holder);
128         setExpanded(isExpanded(disclaimerIndex), disclaimerIndex, holder);
129     }
130 
131     @Override
getItemViewType(int position)132     public int getItemViewType(int position) {
133         if (position == 0) {
134             return VIEW_TYPE_GENERAL_DISCLAIMER;
135         }
136         return VIEW_TYPE_REGULAR_DISCLAIMER;
137     }
138 
setupRootView(int position, String heading, TermsViewHolder viewHolder)139     private void setupRootView(int position, String heading, TermsViewHolder viewHolder) {
140         viewHolder.itemView
141                 .setContentDescription(mContext.getString(R.string.section_heading, heading));
142         viewHolder.itemView.setOnClickListener(view ->
143                 setExpanded(!isExpanded(position), position, viewHolder));
144     }
145 
setupDisclaimerHeading(String heading, TermsViewHolder viewHolder)146     private void setupDisclaimerHeading(String heading, TermsViewHolder viewHolder) {
147         viewHolder.mDisclaimerHeader.setText(heading);
148     }
149 
setupDisclaimerContent(TermsDocument disclaimer, TermsViewHolder viewHolder)150     private void setupDisclaimerContent(TermsDocument disclaimer, TermsViewHolder viewHolder) {
151         TextView disclaimerContent = viewHolder.mDisclaimerContent;
152         TermsAdapterUtils.populateContentTextView(
153                 mContext, disclaimerContent, disclaimer, new ClickableSpanFactory(
154                         mUtils.getAccentColor(mContext),
155                         mTermsBridge::onLinkClicked));
156         mContextMenuMaker.registerWithActivity(disclaimerContent);
157     }
158 
updateViewsForExpandedState(boolean expanded, TermsViewHolder viewHolder)159     private void updateViewsForExpandedState(boolean expanded, TermsViewHolder viewHolder) {
160         viewHolder.mDisclaimerContentContainer.setVisibility(expanded ? View.VISIBLE : View.GONE);
161         viewHolder.mChevron.setRotation(expanded ? 90 : -90);
162     }
163 
164     @Override
getItemCount()165     public int getItemCount() {
166         // First item is always the general disclaimer
167         return 1 + mTermsDocuments.size();
168     }
169 
getDisclaimer(int index)170     private TermsDocument getDisclaimer(int index) {
171         return mTermsDocuments.get(index);
172     }
173 
isExpanded(int position)174     private Boolean isExpanded(int position) {
175         return mTermsBridge.isTermExpanded(position);
176     }
177 
setExpanded(boolean expanded, int position, TermsViewHolder viewHolder)178     private void setExpanded(boolean expanded, int position, TermsViewHolder viewHolder) {
179         mTermsBridge.onTermExpanded(position, expanded);
180         updateViewsForExpandedState(expanded, viewHolder);
181     }
182 
183     /**
184      * Used for communicating with the owner of the adapter.
185      */
186     public interface TermsBridge {
187         /**
188          * Returns whether the disclaimer at position {@code position} is expanded.
189          */
isTermExpanded(int position)190         boolean isTermExpanded(int position);
191 
192         /**
193          * Expands the disclaimer at position {@code position} if {@code expanded} is {@code true},
194          * otherwise collapses it.
195          */
onTermExpanded(int position, boolean expanded)196         void onTermExpanded(int position, boolean expanded);
197 
198         /**
199          * Callback invoked when a link is tapped from the terms content text.
200          * @param intent a web intent ready to be launched.
201          */
onLinkClicked(Intent intent)202         void onLinkClicked(Intent intent);
203     }
204 
205     static class TermsViewHolder extends RecyclerView.ViewHolder {
206         final TextView mGeneralDisclaimer;
207         final TextView mDisclaimerHeader;
208         final TextView mDisclaimerContent;
209         final ViewGroup mDisclaimerContentContainer;
210         final ImageView mChevron;
211 
TermsViewHolder(View itemView)212         TermsViewHolder(View itemView) {
213             super(itemView);
214             mGeneralDisclaimer = itemView.findViewById(R.id.terms_disclaimer_general);
215             mDisclaimerHeader = itemView.findViewById(R.id.sud_items_title);
216             mDisclaimerContent = itemView.findViewById(R.id.disclaimer_content);
217             mDisclaimerContentContainer = itemView.findViewById(R.id.disclaimer_content_container);
218             mChevron = itemView.findViewById(R.id.chevron);
219         }
220     }
221 }
222