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 */
16package com.android.managedprovisioning.preprovisioning.terms;
17
18import static com.android.internal.util.Preconditions.checkNotNull;
19
20import android.text.Spanned;
21import android.text.method.LinkMovementMethod;
22import android.view.LayoutInflater;
23import android.view.View;
24import android.view.ViewGroup;
25import android.view.accessibility.AccessibilityNodeInfo;
26import android.widget.BaseExpandableListAdapter;
27import android.widget.ImageView;
28import android.widget.TextView;
29
30import com.android.managedprovisioning.R;
31import com.android.managedprovisioning.common.AccessibilityContextMenuMaker;
32import com.android.managedprovisioning.common.HtmlToSpannedParser;
33
34import java.util.List;
35
36/**
37 * Allows for displaying {@link TermsDocument} objects in an
38 * {@link android.widget.ExpandableListView}.
39 */
40class TermsListAdapter extends BaseExpandableListAdapter {
41    private final List<TermsDocument> mTermsDocuments;
42    private final LayoutInflater mInflater;
43    private final HtmlToSpannedParser mHtmlToSpannedParser;
44    private final AccessibilityContextMenuMaker mContextMenuMaker;
45    private final GroupExpandedInfo mGroupExpandedInfo;
46
47    /**
48     * Creates a new instance of the class.
49     */
50    TermsListAdapter(List<TermsDocument> termsDocuments, LayoutInflater layoutInflater,
51            AccessibilityContextMenuMaker contextMenuMaker, HtmlToSpannedParser htmlToSpannedParser,
52            GroupExpandedInfo groupExpandedInfo) {
53        mTermsDocuments = checkNotNull(termsDocuments);
54        mInflater = checkNotNull(layoutInflater);
55        mHtmlToSpannedParser = checkNotNull(htmlToSpannedParser);
56        mGroupExpandedInfo = checkNotNull(groupExpandedInfo);
57        mContextMenuMaker = checkNotNull(contextMenuMaker);
58    }
59
60    @Override
61    public int getGroupCount() {
62        return mTermsDocuments.size();
63    }
64
65    @Override
66    public int getChildrenCount(int groupPosition) {
67        return 1; // one content piece per header
68    }
69
70    @Override
71    public TermsDocument getGroup(int groupPosition) {
72        return getDisclaimer(groupPosition);
73    }
74
75    @Override
76    public TermsDocument getChild(int groupPosition, int childPosition) {
77        return getDisclaimer(groupPosition);
78    }
79
80    @Override
81    public long getGroupId(int groupPosition) {
82        return groupPosition;
83    }
84
85    @Override
86    public long getChildId(int groupPosition, int childPosition) {
87        return childPosition;
88    }
89
90    @Override
91    public boolean hasStableIds() {
92        return true;
93    }
94
95    // TODO: encapsulate this logic - too much direct view manipulation
96    @Override
97    public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
98            ViewGroup parent) {
99        String heading = getDisclaimer(groupPosition).getHeading();
100
101        View groupView = convertView != null ? convertView : mInflater.inflate(
102                R.layout.terms_disclaimer_header, parent, false);
103        groupView.setContentDescription(
104                parent.getResources().getString(R.string.section_heading, heading));
105        groupView.setAccessibilityDelegate(new View.AccessibilityDelegate() {
106            @Override public void onInitializeAccessibilityNodeInfo(View host,
107                    AccessibilityNodeInfo info) {
108                super.onInitializeAccessibilityNodeInfo(host, info);
109                info.addAction(new AccessibilityNodeInfo.AccessibilityAction(
110                        AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK.getId(),
111                        parent.getResources().getString(
112                                isExpanded ? R.string.collapse : R.string.expand)));
113            }
114        });
115
116        TextView textView = groupView.findViewById(R.id.header_text);
117        textView.setText(heading);
118
119        ImageView chevron = groupView.findViewById(R.id.chevron);
120        chevron.setRotation(isExpanded ? 90 : -90); // chevron down / up retrospectively
121        groupView.findViewById(R.id.divider).setVisibility(
122                shouldShowGroupDivider(groupPosition) ? View.VISIBLE : View.INVISIBLE);
123
124        return groupView;
125    }
126
127    /**
128     * Helps avoid a double thick divider line: one above header, one from the bottom of prev child
129     */
130    private boolean shouldShowGroupDivider(int groupPosition) {
131        return mGroupExpandedInfo.isGroupExpanded(groupPosition)
132                && (groupPosition == 0 || !mGroupExpandedInfo.isGroupExpanded(groupPosition - 1));
133    }
134
135    // TODO: encapsulate this logic - too much direct view manipulation
136    @Override
137    public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
138            View convertView, ViewGroup parent) {
139        View view = convertView != null ? convertView : mInflater.inflate(
140                R.layout.terms_disclaimer_content, parent, false);
141
142        TermsDocument disclaimer = getDisclaimer(groupPosition);
143        TextView textView = view.findViewById(R.id.disclaimer_content);
144        Spanned content = mHtmlToSpannedParser.parseHtml(disclaimer.getContent());
145        textView.setText(content);
146        textView.setContentDescription(
147                parent.getResources().getString(R.string.section_content, disclaimer.getHeading(),
148                        content));
149        textView.setMovementMethod(LinkMovementMethod.getInstance()); // makes html links clickable
150        mContextMenuMaker.registerWithActivity(textView);
151        return view;
152    }
153
154    private TermsDocument getDisclaimer(int index) {
155        return mTermsDocuments.get(index);
156    }
157
158    @Override
159    public boolean isChildSelectable(int groupPosition, int childPosition) {
160        return false;
161    }
162
163    interface GroupExpandedInfo {
164        boolean isGroupExpanded(int groupPosition);
165    }
166}