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 package com.android.permissioncontroller.permission.ui.handheld;
17 
18 import android.app.ActionBar;
19 import android.content.Context;
20 import android.os.Bundle;
21 import android.widget.ImageView;
22 
23 import androidx.preference.Preference;
24 import androidx.preference.PreferenceScreen;
25 import androidx.preference.PreferenceViewHolder;
26 
27 import com.android.permissioncontroller.R;
28 import com.android.permissioncontroller.permission.model.livedatatypes.PermGroupPackagesUiInfo;
29 import com.android.permissioncontroller.permission.utils.KotlinUtils;
30 import com.android.permissioncontroller.permission.utils.Utils;
31 
32 import java.text.Collator;
33 import java.util.ArrayList;
34 import java.util.HashMap;
35 import java.util.List;
36 import java.util.Map;
37 
38 /**
39  * Superclass for fragments allowing the user to manage permissions.
40  */
41 abstract class ManagePermissionsFragment extends PermissionsFrameFragment
42         implements Preference.OnPreferenceClickListener {
43     private static final String LOG_TAG = "ManagePermissionsFragment";
44 
45     /**
46      * Map<permission names, PermGroupPackagesUiInfo>, representing the data about which
47      * apps are in which permission groups, which to show, and which are granted.
48      */
49     protected Map<String, PermGroupPackagesUiInfo> mPermissionGroups = new HashMap<>();
50     private Collator mCollator;
51 
52     @Override
onCreate(Bundle icicle)53     public void onCreate(Bundle icicle) {
54         super.onCreate(icicle);
55         setHasOptionsMenu(true);
56         final ActionBar ab = getActivity().getActionBar();
57         if (ab != null) {
58             ab.setDisplayHomeAsUpEnabled(true);
59         }
60 
61         mCollator = Collator.getInstance(
62                 getContext().getResources().getConfiguration().getLocales().get(0));
63     }
64 
65     @Override
onPreferenceClick(Preference preference)66     public boolean onPreferenceClick(Preference preference) {
67         String key = preference.getKey();
68 
69         PermGroupPackagesUiInfo group = mPermissionGroups.get(key);
70         if (group == null) {
71             return false;
72         }
73 
74         showPermissionApps(key);
75 
76         return true;
77     }
78 
showPermissionApps(String permissionGroupName)79     abstract void showPermissionApps(String permissionGroupName);
80 
81     /**
82      * Add preferences for all permissions of a type to the preference screen.
83      *
84      * @return The preference screen the permissions were added to
85      */
updatePermissionsUi()86     protected PreferenceScreen updatePermissionsUi() {
87         Context context = getPreferenceManager().getContext();
88         if (context == null || getActivity() == null) {
89             return null;
90         }
91 
92         if (mPermissionGroups == null) {
93             return null;
94         }
95 
96         PreferenceScreen screen = getPreferenceScreen();
97         if (screen == null) {
98             screen = getPreferenceManager().createPreferenceScreen(context);
99             setPreferenceScreen(screen);
100         }
101 
102         List<Preference> toRemove = new ArrayList<>();
103         for (int i = screen.getPreferenceCount() - 1; i >= 0; i--) {
104             Preference group = screen.getPreference(i);
105             if (!mPermissionGroups.containsKey(group.getKey())) {
106                 toRemove.add(group);
107             }
108         }
109 
110         for (Preference pref: toRemove) {
111             screen.removePreference(pref);
112         }
113 
114         for (String groupName : mPermissionGroups.keySet()) {
115 
116             PermGroupPackagesUiInfo group = mPermissionGroups.get(groupName);
117 
118             Preference preference = findPreference(groupName);
119 
120             if (preference == null) {
121                 preference = new FixedSizeIconPreference(context);
122                 preference.setOnPreferenceClickListener(this);
123                 preference.setKey(groupName);
124                 preference.setIcon(Utils.applyTint(context,
125                         KotlinUtils.INSTANCE.getPermGroupIcon(context, groupName),
126                         android.R.attr.colorControlNormal));
127                 preference.setTitle(KotlinUtils.INSTANCE.getPermGroupLabel(context, groupName));
128                 // Set blank summary so that no resizing/jumping happens when the summary is
129                 // loaded.
130                 preference.setSummary(" ");
131                 preference.setPersistent(false);
132                 screen.addPreference(preference);
133             }
134             String summary;
135             if (group != null) {
136                 if (getResources().getBoolean(R.bool.config_useAlternativePermGroupSummary)) {
137                     summary = getString(R.string.app_permissions_group_summary2,
138                             group.getNonSystemGranted(), group.getNonSystemTotal());
139                 } else {
140                     summary = getString(R.string.app_permissions_group_summary,
141                             group.getNonSystemGranted(), group.getNonSystemTotal());
142                 }
143             } else {
144                 summary = getString(R.string.loading);
145             }
146             preference.setSummary(summary);
147         }
148 
149         KotlinUtils.INSTANCE.sortPreferenceGroup(screen, (Preference lhs, Preference rhs) ->
150                 mCollator.compare(lhs.getTitle().toString(), rhs.getTitle().toString()),
151                 false
152         );
153 
154         return screen;
155     }
156 
157     /**
158      * A preference whose icons have the same fixed size. Allows the setting of dividers above and
159      * below the preference.
160      */
161     protected static final class FixedSizeIconPreference extends Preference {
162         private boolean mShowDividerAbove = true;
163         private boolean mShowDividerBelow = false;
164 
FixedSizeIconPreference(Context context)165         FixedSizeIconPreference(Context context) {
166             super(context);
167         }
168 
FixedSizeIconPreference(Context context, boolean dividerAbove, boolean dividerBelow)169         FixedSizeIconPreference(Context context, boolean dividerAbove, boolean dividerBelow) {
170             super(context);
171             mShowDividerAbove = dividerAbove;
172             mShowDividerBelow = dividerBelow;
173         }
174 
175         @Override
onBindViewHolder(PreferenceViewHolder holder)176         public void onBindViewHolder(PreferenceViewHolder holder) {
177             super.onBindViewHolder(holder);
178             ImageView icon = ((ImageView) holder.findViewById(android.R.id.icon));
179             icon.setAdjustViewBounds(true);
180             int size = getContext().getResources().getDimensionPixelSize(
181                     R.dimen.permission_icon_size);
182             icon.setMaxWidth(size);
183             icon.setMaxHeight(size);
184             icon.getLayoutParams().width = size;
185             icon.getLayoutParams().height = size;
186             icon.setScaleType(ImageView.ScaleType.FIT_CENTER);
187 
188             holder.setDividerAllowedAbove(mShowDividerAbove);
189             holder.setDividerAllowedBelow(mShowDividerBelow);
190         }
191     }
192 }
193