1 /*
2  * Copyright (C) 2015 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 
17 package com.android.permissioncontroller.permission.ui.handheld;
18 
19 import android.content.Context;
20 import android.content.Intent;
21 import android.graphics.drawable.Drawable;
22 import android.os.Bundle;
23 import android.os.UserHandle;
24 import android.view.LayoutInflater;
25 import android.view.View;
26 import android.view.ViewGroup;
27 import android.widget.ImageView;
28 import android.widget.TextView;
29 
30 import androidx.annotation.NonNull;
31 import androidx.annotation.Nullable;
32 import androidx.preference.PreferenceCategory;
33 import androidx.preference.PreferenceScreen;
34 import androidx.preference.PreferenceViewHolder;
35 
36 import com.android.permissioncontroller.DeviceUtils;
37 import com.android.permissioncontroller.R;
38 
39 /**
40  * A class that contains a header.
41  */
42 public abstract class SettingsWithLargeHeader extends PermissionsFrameFragment  {
43     static final String HEADER_KEY = " HEADER_PREFERENCE";
44     private static final int HEADER_SORT_FIRST = -2;
45 
46     private View mHeader;
47     private LargeHeaderPreference mHeaderPreference;
48     protected Intent mInfoIntent;
49     protected UserHandle mUserHandle;
50     protected Drawable mIcon;
51     protected CharSequence mLabel;
52     protected boolean mSmallIcon;
53     private View.OnClickListener mListener;
54     private CharSequence mSummary;
55     private boolean mShouldShowHeader = true;
56 
57     @Override
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)58     public View onCreateView(LayoutInflater inflater, ViewGroup container,
59             Bundle savedInstanceState) {
60         ViewGroup root = (ViewGroup) super.onCreateView(inflater, container, savedInstanceState);
61 
62         if (!DeviceUtils.isTelevision(getContext())) {
63             if (mHeader != null && mHeader.getVisibility() == View.VISIBLE) {
64                 updateHeader(mHeader);
65                 mHeader.requireViewById(R.id.header_link).setVisibility(View.VISIBLE);
66             }
67         }
68 
69         return root;
70     }
71 
72     @Override
setPreferenceScreen(PreferenceScreen screen)73     public void setPreferenceScreen(PreferenceScreen screen) {
74         mHeaderPreference = new LargeHeaderPreference(getContext(), this);
75         if (screen.findPreference(HEADER_KEY) == null) {
76             screen.addPreference(mHeaderPreference);
77         }
78         super.setPreferenceScreen(screen);
79     }
80 
81     /**
82      * Set the icon and label to use in the header.
83      *
84      * @param icon the icon
85      * @param label the label
86      * @param infoIntent the intent to show on click
87      * @param smallIcon whether the icon should be small
88      */
setHeader(@onNull Drawable icon, @NonNull CharSequence label, Intent infoIntent, @Nullable UserHandle userHandle, boolean smallIcon)89     public void setHeader(@NonNull Drawable icon, @NonNull CharSequence label,
90             Intent infoIntent, @Nullable UserHandle userHandle, boolean smallIcon) {
91         mIcon = icon;
92         mLabel = label;
93         mInfoIntent = infoIntent;
94         mUserHandle = userHandle;
95         mSmallIcon = smallIcon;
96         if (mHeader != null) {
97             updateHeader(mHeader);
98         }
99     }
100 
101     /**
102      * Updates the header to use the correct icon and title.
103      *
104      * @param header the View that contains the components.
105      */
updateHeader(@ullable View header)106     protected void updateHeader(@Nullable View header) {
107         if (header != null) {
108             header.setVisibility(View.VISIBLE);
109 
110             ImageView appIcon = header.requireViewById(R.id.entity_header_icon);
111             appIcon.setImageDrawable(mIcon);
112             if (mSmallIcon) {
113                 int size = getContext().getResources().getDimensionPixelSize(
114                         R.dimen.permission_icon_header_size);
115                 appIcon.getLayoutParams().width = size;
116                 appIcon.getLayoutParams().height = size;
117             }
118             if (mInfoIntent != null) {
119                 appIcon.setOnClickListener(v -> getActivity().startActivityAsUser(mInfoIntent,
120                         mUserHandle));
121                 appIcon.setContentDescription(mLabel);
122             }
123 
124             TextView appName = header.requireViewById(R.id.entity_header_title);
125             appName.setText(mLabel);
126 
127             header.requireViewById(R.id.entity_header_summary).setVisibility(View.GONE);
128             header.requireViewById(R.id.entity_header_second_summary).setVisibility(View.GONE);
129             header.requireViewById(R.id.header_link).setVisibility(View.GONE);
130         }
131     }
132 
133     /**
134      * Hide the entire header.
135      */
hideHeader()136     public void hideHeader() {
137         if (mHeaderPreference == null) {
138             mShouldShowHeader = false;
139             return;
140         }
141         mHeaderPreference.setVisible(false);
142         mHeader = null;
143     }
144 
145     /**
146      * Set the summary text in the header. If the header has not been created yet, then save the
147      * the summary for later.
148      *
149      * @param summary the text to display
150      * @param listener the click listener if the summary should be clickable
151      */
setSummary(@onNull CharSequence summary, @Nullable View.OnClickListener listener)152     public void setSummary(@NonNull CharSequence summary, @Nullable View.OnClickListener listener) {
153         if (mHeader == null) {
154             mSummary = summary;
155             mListener = listener;
156             return;
157         }
158         TextView textView = mHeader.requireViewById(R.id.header_text);
159         TextView linkView = mHeader.requireViewById(R.id.header_link);
160         if (listener != null) {
161             linkView.setOnClickListener(listener);
162             linkView.setVisibility(View.VISIBLE);
163             linkView.setText(summary);
164             textView.setVisibility(View.GONE);
165         } else {
166             textView.setVisibility(View.VISIBLE);
167             textView.setText(summary);
168             linkView.setVisibility(View.GONE);
169         }
170     }
171 
172     /**
173      * A Preference that will act as the "Large Header" for "SettingsWithLargeHeader" fragments.
174      */
175     public static class LargeHeaderPreference extends PreferenceCategory {
176         private SettingsWithLargeHeader mFragment;
177 
LargeHeaderPreference(Context context, SettingsWithLargeHeader fragment)178         private LargeHeaderPreference(Context context, SettingsWithLargeHeader fragment) {
179             super(context);
180             mFragment = fragment;
181             setVisible(mFragment.mShouldShowHeader);
182             setSelectable(false);
183             setLayoutResource(R.layout.header_large);
184             setKey(HEADER_KEY);
185 
186             // display the header first (lower numbers are ordered higher)
187             setOrder(HEADER_SORT_FIRST);
188         }
189 
190         @Override
onBindViewHolder(PreferenceViewHolder holder)191         public void onBindViewHolder(PreferenceViewHolder holder) {
192             if (!isVisible()) {
193                 return;
194             }
195             super.onBindViewHolder(holder);
196 
197             View view = holder.itemView;
198             if (view == mFragment.mHeader) {
199                 return;
200             }
201             mFragment.mHeader = view;
202             if (mFragment.mIcon != null) {
203                 mFragment.updateHeader(view);
204             }
205             if (mFragment.mSummary != null) {
206                 mFragment.setSummary(mFragment.mSummary, mFragment.mListener);
207             }
208         }
209     }
210 }
211