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