• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 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.permissioncontroller.permission.ui.handheld;
17 
18 import static androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory;
19 
20 import static com.android.permissioncontroller.Constants.EXTRA_SESSION_ID;
21 import static com.android.permissioncontroller.Constants.INVALID_SESSION_ID;
22 import static com.android.permissioncontroller.permission.ui.handheld.UtilsKt.pressBack;
23 
24 import android.app.Application;
25 import android.os.Bundle;
26 import android.util.Log;
27 import android.view.MenuItem;
28 
29 import androidx.lifecycle.ViewModelProvider;
30 import androidx.preference.Preference;
31 import androidx.preference.PreferenceScreen;
32 
33 import com.android.modules.utils.build.SdkLevel;
34 import com.android.permission.flags.Flags;
35 import com.android.permissioncontroller.R;
36 import com.android.permissioncontroller.permission.data.PermGroupsPackagesUiInfoLiveData;
37 import com.android.permissioncontroller.permission.ui.UnusedAppsFragment;
38 import com.android.permissioncontroller.permission.ui.model.ManageStandardPermissionsViewModel;
39 import com.android.permissioncontroller.permission.utils.StringUtils;
40 import com.android.permissioncontroller.permission.utils.Utils;
41 
42 /**
43  * Fragment that allows the user to manage standard permissions.
44  */
45 public final class ManageStandardPermissionsFragment extends ManagePermissionsFragment {
46     private static final String EXTRA_PREFS_KEY = "extra_prefs_key";
47     private static final String AUTO_REVOKE_KEY = "auto_revoke_key";
48     private static final String LOG_TAG = ManageStandardPermissionsFragment.class.getSimpleName();
49     private ManageStandardPermissionsViewModel mViewModel;
50 
51     /**
52      * Create a bundle with the arguments needed by this fragment
53      *
54      * @param sessionId The current session ID
55      * @return A bundle with all of the args placed
56      */
createArgs(long sessionId)57     public static Bundle createArgs(long sessionId) {
58         Bundle arguments = new Bundle();
59         arguments.putLong(EXTRA_SESSION_ID, sessionId);
60         return arguments;
61     }
62 
getPermGroupsLiveData()63     private PermGroupsPackagesUiInfoLiveData getPermGroupsLiveData() {
64         if (Flags.declutteredPermissionManagerEnabled()) {
65             return mViewModel.getUsedStandardPermGroupsUiInfo();
66         } else {
67             return mViewModel.getUiDataLiveData();
68         }
69     }
70 
71     @Override
onCreate(Bundle icicle)72     public void onCreate(Bundle icicle) {
73         super.onCreate(icicle);
74 
75         final Application application = getActivity().getApplication();
76         mViewModel = new ViewModelProvider(this, AndroidViewModelFactory.getInstance(application))
77                 .get(ManageStandardPermissionsViewModel.class);
78         mPermissionGroups = getPermGroupsLiveData().getValue();
79 
80         getPermGroupsLiveData().observe(this, permissionGroups -> {
81             // Once we have loaded data for the first time, further loads should be staggered,
82             // for performance reasons.
83             getPermGroupsLiveData().setLoadStaggered(true);
84             if (permissionGroups != null) {
85                 mPermissionGroups = permissionGroups;
86                 updatePermissionsUi();
87             } else {
88                 Log.e(LOG_TAG, "ViewModel returned null data, exiting");
89                 getActivity().finishAfterTransition();
90             }
91 
92             // If we've loaded all LiveDatas, no need to prioritize loading any particular one
93             if (!getPermGroupsLiveData().isStale()) {
94                 getPermGroupsLiveData().setFirstLoadGroup(null);
95             }
96         });
97 
98         mViewModel.getNumCustomPermGroups().observe(this, permNames -> updatePermissionsUi());
99         mViewModel.getNumAutoRevoked().observe(this, show -> updatePermissionsUi());
100         if (Flags.declutteredPermissionManagerEnabled()) {
101             mViewModel.getNumUnusedStandardPermGroups().observe(
102                     this, show -> updatePermissionsUi()
103             );
104         }
105     }
106 
107     @Override
onStart()108     public void onStart() {
109         super.onStart();
110 
111         getActivity().setTitle(com.android.permissioncontroller.R.string.app_permission_manager);
112     }
113 
114     @Override
onOptionsItemSelected(MenuItem item)115     public boolean onOptionsItemSelected(MenuItem item) {
116         switch (item.getItemId()) {
117             case android.R.id.home:
118                 pressBack(this);
119                 return true;
120         }
121         return super.onOptionsItemSelected(item);
122     }
123 
124     @Override
updatePermissionsUi()125     protected PreferenceScreen updatePermissionsUi() {
126         PreferenceScreen screen = super.updatePermissionsUi();
127         if (screen == null) {
128             return null;
129         }
130 
131         // Check if we need an additional permissions preference
132         int numExtraPermissions = 0;
133         if (mViewModel.getNumCustomPermGroups().getValue() != null) {
134             numExtraPermissions = mViewModel.getNumCustomPermGroups().getValue();
135         }
136         if (Flags.declutteredPermissionManagerEnabled()) {
137             if (mViewModel.getNumUnusedStandardPermGroups().getValue() != null) {
138                 // When decluttered permission manager is enabled, unused
139                 // permission groups will also be displayed in the additional
140                 // permissions screen.
141                 numExtraPermissions += mViewModel.getNumUnusedStandardPermGroups().getValue();
142             }
143         }
144 
145         Preference additionalPermissionsPreference = screen.findPreference(EXTRA_PREFS_KEY);
146         if (numExtraPermissions == 0) {
147             if (additionalPermissionsPreference != null) {
148                 screen.removePreference(additionalPermissionsPreference);
149             }
150         } else {
151             if (additionalPermissionsPreference == null) {
152                 additionalPermissionsPreference = new FixedSizeIconPreference(
153                         getPreferenceManager().getContext());
154                 additionalPermissionsPreference.setKey(EXTRA_PREFS_KEY);
155                 additionalPermissionsPreference.setIcon(Utils.applyTint(getActivity(),
156                         R.drawable.ic_more_items,
157                         android.R.attr.colorControlNormal));
158                 additionalPermissionsPreference.setTitle(R.string.additional_permissions);
159                 additionalPermissionsPreference.setOnPreferenceClickListener(preference -> {
160                     mViewModel.showCustomPermissions(this,
161                             ManageCustomPermissionsFragment.createArgs(
162                                     getArguments().getLong(EXTRA_SESSION_ID)));
163                     return true;
164                 });
165 
166                 screen.addPreference(additionalPermissionsPreference);
167             }
168 
169             additionalPermissionsPreference.setSummary(StringUtils.getIcuPluralsString(getContext(),
170                     R.string.additional_permissions_more, numExtraPermissions));
171         }
172 
173         Integer numAutoRevoked = mViewModel.getNumAutoRevoked().getValue();
174 
175         Preference autoRevokePreference = screen.findPreference(AUTO_REVOKE_KEY);
176         if (numAutoRevoked != null && numAutoRevoked != 0) {
177             if (autoRevokePreference == null) {
178                 if (SdkLevel.isAtLeastS()) {
179                     autoRevokePreference = createAutoRevokeFooterPreferenceForSPlus();
180                 } else {
181                     autoRevokePreference = createAutoRevokeFooterPreferenceForR();
182                 }
183                 autoRevokePreference.setKey(AUTO_REVOKE_KEY);
184                 screen.addPreference(autoRevokePreference);
185             }
186         } else if (numAutoRevoked != null && autoRevokePreference != null) {
187             screen.removePreference(autoRevokePreference);
188         }
189 
190         return screen;
191     }
192 
createAutoRevokeFooterPreferenceForSPlus()193     private PermissionFooterPreference createAutoRevokeFooterPreferenceForSPlus() {
194         PermissionFooterPreference autoRevokePreference =
195                 new PermissionFooterPreference(getContext());
196         autoRevokePreference.setSummary(R.string.auto_revoked_apps_page_summary);
197         autoRevokePreference.setLearnMoreAction(view -> {
198             mViewModel.showAutoRevoke(this, UnusedAppsFragment.createArgs(
199                             getArguments().getLong(EXTRA_SESSION_ID, INVALID_SESSION_ID)));
200             });
201         return autoRevokePreference;
202     }
203 
createAutoRevokeFooterPreferenceForR()204     private Preference createAutoRevokeFooterPreferenceForR() {
205         Preference autoRevokePreference = new FixedSizeIconPreference(
206                 getPreferenceManager().getContext(), true, true);
207         autoRevokePreference.setOrder(-1);
208         autoRevokePreference.setSingleLineTitle(false);
209         autoRevokePreference.setIcon(R.drawable.ic_info_outline_accent);
210         autoRevokePreference.setTitle(R.string.auto_revoke_permission_notification_title);
211         autoRevokePreference.setSummary(R.string.auto_revoke_setting_subtitle);
212         autoRevokePreference.setOnPreferenceClickListener(preference -> {
213             mViewModel.showAutoRevoke(this, UnusedAppsFragment.createArgs(
214                     getArguments().getLong(EXTRA_SESSION_ID, INVALID_SESSION_ID)));
215             return true;
216         });
217         return autoRevokePreference;
218     }
219 
220     @Override
showPermissionApps(String permissionGroupName)221     public void showPermissionApps(String permissionGroupName) {
222         // If we return to this page within a reasonable time, prioritize loading data from the
223         // permission group whose page we are going to, as that is group most likely to have changed
224         getPermGroupsLiveData().setFirstLoadGroup(permissionGroupName);
225         mViewModel.showPermissionApps(this, PermissionAppsFragment.createArgs(
226                 permissionGroupName, getArguments().getLong(EXTRA_SESSION_ID)));
227     }
228 }
229