1 /* 2 * Copyright (C) 2017 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.settings.applications.appinfo; 18 19 import android.app.Activity; 20 import android.content.ActivityNotFoundException; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.content.pm.PackageManager; 24 import android.content.res.Resources; 25 import android.icu.text.ListFormatter; 26 import android.util.Log; 27 28 import androidx.annotation.VisibleForTesting; 29 import androidx.preference.Preference; 30 31 import com.android.settings.R; 32 import com.android.settingslib.applications.PermissionsSummaryHelper; 33 import com.android.settingslib.core.lifecycle.LifecycleObserver; 34 import com.android.settingslib.core.lifecycle.events.OnStart; 35 import com.android.settingslib.core.lifecycle.events.OnStop; 36 37 import java.util.ArrayList; 38 import java.util.List; 39 import java.util.Random; 40 41 /** 42 * A PreferenceController handling the logic for permissions of apps. 43 */ 44 public class AppPermissionPreferenceController extends AppInfoPreferenceControllerBase implements 45 LifecycleObserver, OnStart, OnStop { 46 47 private static final String TAG = "PermissionPrefControl"; 48 private static final String EXTRA_HIDE_INFO_BUTTON = "hideInfoButton"; 49 private static final long INVALID_SESSION_ID = 0; 50 51 private final PackageManager mPackageManager; 52 53 private String mPackageName; 54 55 @VisibleForTesting 56 final PermissionsSummaryHelper.PermissionsResultCallback mPermissionCallback 57 = new PermissionsSummaryHelper.PermissionsResultCallback() { 58 @Override 59 public void onPermissionSummaryResult(int standardGrantedPermissionCount, 60 int requestedPermissionCount, int additionalGrantedPermissionCount, 61 List<CharSequence> grantedGroupLabels) { 62 final Resources res = mContext.getResources(); 63 CharSequence summary; 64 65 if (requestedPermissionCount == 0) { 66 summary = res.getString( 67 R.string.runtime_permissions_summary_no_permissions_requested); 68 mPreference.setEnabled(false); 69 } else { 70 final ArrayList<CharSequence> list = new ArrayList<>(grantedGroupLabels); 71 if (additionalGrantedPermissionCount > 0) { 72 // N additional permissions. 73 list.add(res.getQuantityString( 74 R.plurals.runtime_permissions_additional_count, 75 additionalGrantedPermissionCount, additionalGrantedPermissionCount)); 76 } 77 if (list.size() == 0) { 78 summary = res.getString( 79 R.string.runtime_permissions_summary_no_permissions_granted); 80 } else { 81 summary = ListFormatter.getInstance().format(list); 82 } 83 mPreference.setEnabled(true); 84 } 85 mPreference.setSummary(summary); 86 } 87 }; 88 89 private final PackageManager.OnPermissionsChangedListener mOnPermissionsChangedListener = 90 uid -> updateState(mPreference); 91 AppPermissionPreferenceController(Context context, String key)92 public AppPermissionPreferenceController(Context context, String key) { 93 super(context, key); 94 mPackageManager = context.getPackageManager(); 95 } 96 97 @Override onStart()98 public void onStart() { 99 mPackageManager.addOnPermissionsChangeListener(mOnPermissionsChangedListener); 100 } 101 102 @Override onStop()103 public void onStop() { 104 mPackageManager.removeOnPermissionsChangeListener(mOnPermissionsChangedListener); 105 } 106 107 @Override updateState(Preference preference)108 public void updateState(Preference preference) { 109 PermissionsSummaryHelper.getPermissionSummary(mContext, mPackageName, mPermissionCallback); 110 } 111 112 @Override handlePreferenceTreeClick(Preference preference)113 public boolean handlePreferenceTreeClick(Preference preference) { 114 if (getPreferenceKey().equals(preference.getKey())) { 115 startManagePermissionsActivity(); 116 return true; 117 } 118 return false; 119 } 120 setPackageName(String packageName)121 public void setPackageName(String packageName) { 122 mPackageName = packageName; 123 } 124 startManagePermissionsActivity()125 private void startManagePermissionsActivity() { 126 // start new activity to manage app permissions 127 final Intent permIntent = new Intent(Intent.ACTION_MANAGE_APP_PERMISSIONS); 128 permIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, mParent.getAppEntry().info.packageName); 129 permIntent.putExtra(EXTRA_HIDE_INFO_BUTTON, true); 130 Activity activity = mParent.getActivity(); 131 Intent intent = activity != null ? activity.getIntent() : null; 132 if (intent != null) { 133 String action = intent.getAction(); 134 long sessionId = intent.getLongExtra( 135 Intent.ACTION_AUTO_REVOKE_PERMISSIONS, INVALID_SESSION_ID); 136 if ((action != null && action.equals(Intent.ACTION_AUTO_REVOKE_PERMISSIONS)) 137 || sessionId != INVALID_SESSION_ID) { 138 // If intent is Auto revoke, and we don't already have a session ID, make one 139 while (sessionId == INVALID_SESSION_ID) { 140 sessionId = new Random().nextLong(); 141 } 142 permIntent.putExtra(Intent.ACTION_AUTO_REVOKE_PERMISSIONS, sessionId); 143 } 144 } 145 try { 146 if (activity != null) { 147 activity.startActivityForResult(permIntent, mParent.SUB_INFO_FRAGMENT); 148 } 149 } catch (ActivityNotFoundException e) { 150 Log.w(TAG, "No app can handle android.intent.action.MANAGE_APP_PERMISSIONS"); 151 } 152 } 153 } 154