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