blob: 999ca591102b8594b366a41eaa35c288fd567ecc [file] [log] [blame]
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.permissioncontroller.permission.ui.handheld;
import static com.android.permissioncontroller.Constants.EXTRA_SESSION_ID;
import static com.android.permissioncontroller.Constants.INVALID_SESSION_ID;
import static com.android.permissioncontroller.PermissionControllerStatsLog.APP_PERMISSIONS_FRAGMENT_VIEWED;
import static com.android.permissioncontroller.PermissionControllerStatsLog.APP_PERMISSIONS_FRAGMENT_VIEWED__CATEGORY__ALLOWED;
import static com.android.permissioncontroller.PermissionControllerStatsLog.APP_PERMISSIONS_FRAGMENT_VIEWED__CATEGORY__ALLOWED_FOREGROUND;
import static com.android.permissioncontroller.PermissionControllerStatsLog.APP_PERMISSIONS_FRAGMENT_VIEWED__CATEGORY__DENIED;
import static com.android.permissioncontroller.hibernation.HibernationPolicyKt.isHibernationEnabled;
import static com.android.permissioncontroller.permission.ui.handheld.UtilsKt.pressBack;
import static com.android.permissioncontroller.permission.utils.Utils.LAST_24H_CONTENT_PROVIDER;
import static com.android.permissioncontroller.permission.utils.Utils.LAST_24H_SENSOR_TODAY;
import static com.android.permissioncontroller.permission.utils.Utils.LAST_24H_SENSOR_YESTERDAY;
import static com.android.permissioncontroller.permission.utils.Utils.NOT_IN_LAST_24H;
import static java.util.concurrent.TimeUnit.DAYS;
import android.app.ActionBar;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.drawable.Drawable;
import android.icu.text.ListFormatter;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.annotation.StringRes;
import androidx.lifecycle.ViewModelProvider;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceScreen;
import androidx.preference.SwitchPreference;
import com.android.modules.utils.build.SdkLevel;
import com.android.permissioncontroller.PermissionControllerStatsLog;
import com.android.permissioncontroller.R;
import com.android.permissioncontroller.permission.model.AppPermissionUsage;
import com.android.permissioncontroller.permission.model.livedatatypes.HibernationSettingState;
import com.android.permissioncontroller.permission.ui.Category;
import com.android.permissioncontroller.permission.ui.handheld.dashboard.PermissionUsages;
import com.android.permissioncontroller.permission.ui.model.AppPermissionGroupsViewModel;
import com.android.permissioncontroller.permission.ui.model.AppPermissionGroupsViewModel.GroupUiInfo;
import com.android.permissioncontroller.permission.ui.model.AppPermissionGroupsViewModelFactory;
import com.android.permissioncontroller.permission.utils.KotlinUtils;
import com.android.permissioncontroller.permission.utils.Utils;
import com.android.settingslib.HelpUtils;
import com.android.settingslib.widget.FooterPreference;
import java.text.Collator;
import java.time.Instant;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Random;
import kotlin.Pair;
/**
* Show and manage permission groups for an app.
*
* <p>Shows the list of permission groups the app has requested at one permission for.
*/
public final class AppPermissionGroupsFragment extends SettingsWithLargeHeader implements
PermissionUsages.PermissionsUsagesChangeCallback {
private static final String LOG_TAG = AppPermissionGroupsFragment.class.getSimpleName();
private static final String IS_SYSTEM_PERMS_SCREEN = "_is_system_screen";
private static final String AUTO_REVOKE_CATEGORY_KEY = "_AUTO_REVOKE_KEY";
private static final String AUTO_REVOKE_SWITCH_KEY = "_AUTO_REVOKE_SWITCH_KEY";
private static final String AUTO_REVOKE_SUMMARY_KEY = "_AUTO_REVOKE_SUMMARY_KEY";
private static final String ASSISTANT_MIC_CATEGORY_KEY = "_ASSISTANT_MIC_KEY";
private static final String ASSISTANT_MIC_SWITCH_KEY = "_ASSISTANT_MIC_SWITCH_KEY";
private static final String ASSISTANT_MIC_SUMMARY_KEY = "_ASSISTANT_MIC_SUMMARY_KEY";
private static final int AGGREGATE_DATA_FILTER_BEGIN_DAYS = 1;
static final String EXTRA_HIDE_INFO_BUTTON = "hideInfoButton";
private AppPermissionGroupsViewModel mViewModel;
private boolean mIsSystemPermsScreen;
private boolean mIsFirstLoad;
private String mPackageName;
private UserHandle mUser;
private PermissionUsages mPermissionUsages;
private List<AppPermissionUsage> mAppPermissionUsages = new ArrayList<>();
private Collator mCollator;
/**
* Create a bundle with the arguments needed by this fragment
*
* @param packageName The name of the package
* @param userHandle The user of this package
* @param sessionId The current session ID
* @param isSystemPermsScreen Whether or not this screen is the system permission screen, or
* the extra permissions screen
*
* @return A bundle with all of the args placed
*/
public static Bundle createArgs(@NonNull String packageName, @NonNull UserHandle userHandle,
long sessionId, boolean isSystemPermsScreen) {
Bundle arguments = new Bundle();
arguments.putString(Intent.EXTRA_PACKAGE_NAME, packageName);
arguments.putParcelable(Intent.EXTRA_USER, userHandle);
arguments.putLong(EXTRA_SESSION_ID, sessionId);
arguments.putBoolean(IS_SYSTEM_PERMS_SCREEN, isSystemPermsScreen);
return arguments;
}
/**
* Create a bundle for a system permissions fragment
*
* @param packageName The name of the package
* @param userHandle The user of this package
* @param sessionId The current session ID
*
* @return A bundle with all of the args placed
*/
public static Bundle createArgs(@NonNull String packageName, @NonNull UserHandle userHandle,
long sessionId) {
return createArgs(packageName, userHandle, sessionId, true);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
mIsFirstLoad = true;
final ActionBar ab = getActivity().getActionBar();
if (ab != null) {
ab.setDisplayHomeAsUpEnabled(true);
}
mPackageName = getArguments().getString(Intent.EXTRA_PACKAGE_NAME);
mUser = getArguments().getParcelable(Intent.EXTRA_USER);
mIsSystemPermsScreen = getArguments().getBoolean(IS_SYSTEM_PERMS_SCREEN, true);
AppPermissionGroupsViewModelFactory factory =
new AppPermissionGroupsViewModelFactory(mPackageName, mUser,
getArguments().getLong(EXTRA_SESSION_ID, 0));
mViewModel = new ViewModelProvider(this, factory).get(AppPermissionGroupsViewModel.class);
mViewModel.getPackagePermGroupsLiveData().observe(this, this::updatePreferences);
mViewModel.getAutoRevokeLiveData().observe(this, this::setAutoRevokeToggleState);
mCollator = Collator.getInstance(
getContext().getResources().getConfiguration().getLocales().get(0));
// If the build type is below S, the app ops for permission usage can't be found. Thus, we
// shouldn't load permission usages, for them.
if (SdkLevel.isAtLeastS()) {
Context context = getPreferenceManager().getContext();
mPermissionUsages = new PermissionUsages(context);
long filterTimeBeginMillis = Math.max(System.currentTimeMillis()
- DAYS.toMillis(AGGREGATE_DATA_FILTER_BEGIN_DAYS),
Instant.EPOCH.toEpochMilli());
mPermissionUsages.load(null, null, filterTimeBeginMillis, Long.MAX_VALUE,
PermissionUsages.USAGE_FLAG_LAST, getActivity().getLoaderManager(),
false, false, this, false);
}
updatePreferences(mViewModel.getPackagePermGroupsLiveData().getValue());
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
getActivity().setTitle(R.string.app_permissions);
return super.onCreateView(inflater, container, savedInstanceState);
}
@Override
@RequiresApi(Build.VERSION_CODES.S)
public void onPermissionUsagesChanged() {
if (mPermissionUsages.getUsages().isEmpty()) {
return;
}
if (getContext() == null) {
// Async result has come in after our context is gone.
return;
}
mAppPermissionUsages = new ArrayList<>(mPermissionUsages.getUsages());
updatePreferences(mViewModel.getPackagePermGroupsLiveData().getValue());
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home: {
pressBack(this);
return true;
}
case MENU_ALL_PERMS: {
mViewModel.showAllPermissions(this, AllAppPermissionsFragment.createArgs(
mPackageName, mUser));
return true;
}
}
return super.onOptionsItemSelected(item);
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
if (mIsSystemPermsScreen) {
menu.add(Menu.NONE, MENU_ALL_PERMS, Menu.NONE, R.string.all_permissions);
if (!SdkLevel.isAtLeastS()) {
HelpUtils.prepareHelpMenuItem(getActivity(), menu, R.string.help_app_permissions,
getClass().getName());
}
}
}
private static void bindUi(SettingsWithLargeHeader fragment, String packageName,
UserHandle user) {
Activity activity = fragment.getActivity();
Intent infoIntent = null;
if (!activity.getIntent().getBooleanExtra(EXTRA_HIDE_INFO_BUTTON, false)) {
infoIntent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
.setData(Uri.fromParts("package", packageName, null));
}
Drawable icon = KotlinUtils.INSTANCE.getBadgedPackageIcon(activity.getApplication(),
packageName, user);
fragment.setHeader(icon, KotlinUtils.INSTANCE.getPackageLabel(activity.getApplication(),
packageName, user), infoIntent, user, false);
}
private void createPreferenceScreenIfNeeded() {
if (getPreferenceScreen() == null) {
addPreferencesFromResource(R.xml.allowed_denied);
addAutoRevokePreferences(getPreferenceScreen());
bindUi(this, mPackageName, mUser);
}
}
private void extractGroupUsageLastAccessTime(Map<String, Long> accessTime) {
accessTime.clear();
long filterTimeBeginMillis = Math.max(System.currentTimeMillis()
- DAYS.toMillis(AGGREGATE_DATA_FILTER_BEGIN_DAYS), Instant.EPOCH.toEpochMilli());
int numApps = mAppPermissionUsages.size();
for (int appIndex = 0; appIndex < numApps; appIndex++) {
AppPermissionUsage appUsage = mAppPermissionUsages.get(appIndex);
if (!appUsage.getPackageName().equals(mPackageName)) {
continue;
}
List<AppPermissionUsage.GroupUsage> appGroups = appUsage.getGroupUsages();
int numGroups = appGroups.size();
for (int groupIndex = 0; groupIndex < numGroups; groupIndex++) {
AppPermissionUsage.GroupUsage groupUsage = appGroups.get(groupIndex);
long lastAccessTime = groupUsage.getLastAccessTime();
String groupName = groupUsage.getGroup().getName();
if (lastAccessTime == 0 || lastAccessTime < filterTimeBeginMillis) {
continue;
}
// We might have another AppPermissionUsage entry that's of the same packageName
// but with a different uid. In that case, we want to grab the max lastAccessTime
// as the last usage to show.
lastAccessTime = Math.max(
accessTime.getOrDefault(groupName, Instant.EPOCH.toEpochMilli()),
lastAccessTime);
accessTime.put(groupName, lastAccessTime);
}
}
}
private void updatePreferences(Map<Category, List<GroupUiInfo>> groupMap) {
if (groupMap == null) {
return;
}
createPreferenceScreenIfNeeded();
Context context = getPreferenceManager().getContext();
if (context == null) {
return;
}
if (groupMap == null && mViewModel.getPackagePermGroupsLiveData().isInitialized()) {
Toast.makeText(
getActivity(), R.string.app_not_found_dlg_title, Toast.LENGTH_LONG).show();
Log.w(LOG_TAG, "invalid package " + mPackageName);
pressBack(this);
return;
}
Map<String, Long> groupUsageLastAccessTime = new HashMap<>();
extractGroupUsageLastAccessTime(groupUsageLastAccessTime);
findPreference(Category.ALLOWED_FOREGROUND.getCategoryName()).setVisible(false);
long sessionId = getArguments().getLong(EXTRA_SESSION_ID, INVALID_SESSION_ID);
for (Category grantCategory : groupMap.keySet()) {
PreferenceCategory category = findPreference(grantCategory.getCategoryName());
int numExtraPerms = 0;
category.removeAll();
if (grantCategory.equals(Category.ALLOWED_FOREGROUND)) {
category.setVisible(false);
category = findPreference(Category.ALLOWED.getCategoryName());
}
if (grantCategory.equals(Category.ASK)) {
if (groupMap.get(grantCategory).size() == 0) {
category.setVisible(false);
} else {
category.setVisible(true);
}
}
for (GroupUiInfo groupInfo : groupMap.get(grantCategory)) {
String groupName = groupInfo.getGroupName();
Long lastAccessTime = groupUsageLastAccessTime.get(groupName);
Pair<String, Integer> summaryTimestamp = Utils
.getPermissionLastAccessSummaryTimestamp(
lastAccessTime, context, groupName);
@Utils.AppPermsLastAccessType int lastAccessType = summaryTimestamp.getSecond();
PermissionControlPreference preference = new PermissionControlPreference(context,
mPackageName, groupName, mUser, AppPermissionGroupsFragment.class.getName(),
sessionId, grantCategory.getCategoryName(), true);
preference.setTitle(KotlinUtils.INSTANCE.getPermGroupLabel(context, groupName));
preference.setIcon(KotlinUtils.INSTANCE.getPermGroupIcon(context, groupName));
preference.setKey(groupName);
switch (groupInfo.getSubtitle()) {
case BACKGROUND:
switch (lastAccessType) {
case LAST_24H_CONTENT_PROVIDER:
preference.setSummary(
R.string.app_perms_content_provider_background);
break;
case LAST_24H_SENSOR_TODAY:
preference.setSummary(
getString(
R.string.app_perms_24h_access_background,
summaryTimestamp.getFirst()));
break;
case LAST_24H_SENSOR_YESTERDAY:
preference.setSummary(getString(
R.string.app_perms_24h_access_yest_background,
summaryTimestamp.getFirst()));
break;
case NOT_IN_LAST_24H:
default:
preference.setSummary(
R.string.permission_subtitle_background);
}
break;
case MEDIA_ONLY:
switch (lastAccessType) {
case LAST_24H_CONTENT_PROVIDER:
preference.setSummary(
R.string.app_perms_content_provider_media_only);
break;
case LAST_24H_SENSOR_TODAY:
preference.setSummary(
getString(
R.string.app_perms_24h_access_media_only,
summaryTimestamp.getFirst()));
break;
case LAST_24H_SENSOR_YESTERDAY:
preference.setSummary(
getString(
R.string.app_perms_24h_access_yest_media_only,
summaryTimestamp.getFirst()));
break;
case NOT_IN_LAST_24H:
default:
preference.setSummary(R.string.permission_subtitle_media_only);
}
break;
case ALL_FILES:
switch (lastAccessType) {
case LAST_24H_CONTENT_PROVIDER:
preference.setSummary(
R.string.app_perms_content_provider_all_files);
break;
case LAST_24H_SENSOR_TODAY:
preference.setSummary(
getString(
R.string.app_perms_24h_access_all_files,
summaryTimestamp.getFirst()));
break;
case LAST_24H_SENSOR_YESTERDAY:
preference.setSummary(
getString(
R.string.app_perms_24h_access_yest_all_files,
summaryTimestamp.getFirst()));
break;
case NOT_IN_LAST_24H:
default:
preference.setSummary(R.string.permission_subtitle_all_files);
}
break;
case FOREGROUND_ONLY:
// We don't want to note the foreground access
default:
switch (lastAccessType) {
case LAST_24H_CONTENT_PROVIDER:
preference.setSummary(
R.string.app_perms_content_provider);
break;
case LAST_24H_SENSOR_TODAY:
preference.setSummary(
getString(R.string.app_perms_24h_access,
summaryTimestamp.getFirst()));
break;
case LAST_24H_SENSOR_YESTERDAY:
preference.setSummary(
getString(R.string.app_perms_24h_access_yest,
summaryTimestamp.getFirst()));
break;
case NOT_IN_LAST_24H:
default:
}
}
// Add an info icon if the package handles ACTION_VIEW_PERMISSION_USAGE.
PackageManager packageManager = requireActivity().getPackageManager();
Intent viewUsageIntent = new Intent()
.setPackage(mPackageName)
.setAction(Intent.ACTION_VIEW_PERMISSION_USAGE)
.putExtra(Intent.EXTRA_PERMISSION_GROUP_NAME, groupName);
ResolveInfo resolveInfo = packageManager.resolveActivity(viewUsageIntent,
PackageManager.MATCH_INSTANT);
if (resolveInfo != null && resolveInfo.activityInfo != null && Objects.equals(
resolveInfo.activityInfo.permission,
android.Manifest.permission.START_VIEW_PERMISSION_USAGE)) {
// Make the intent explicit to not require CATEGORY_DEFAULT.
viewUsageIntent.setComponent(new ComponentName(
resolveInfo.activityInfo.packageName, resolveInfo.activityInfo.name));
preference.setRightIcon(
context.getDrawable(R.drawable.ic_info_outline),
v -> {
try {
startActivity(viewUsageIntent);
} catch (ActivityNotFoundException e) {
Log.e(LOG_TAG, "No activity found for viewing permission "
+ "usage.");
}
});
}
if (groupInfo.isSystem() == mIsSystemPermsScreen) {
category.addPreference(preference);
} else if (!groupInfo.isSystem()) {
numExtraPerms++;
}
}
int noPermsStringRes = grantCategory.equals(Category.DENIED)
? R.string.no_permissions_denied : R.string.no_permissions_allowed;
if (numExtraPerms > 0) {
final Preference extraPerms = setUpCustomPermissionsScreen(context, numExtraPerms,
grantCategory.getCategoryName());
category.addPreference(extraPerms);
}
if (category.getPreferenceCount() == 0) {
setNoPermissionPreference(category, noPermsStringRes, context);
}
KotlinUtils.INSTANCE.sortPreferenceGroup(category, this::comparePreferences, false);
}
setAutoRevokeToggleState(mViewModel.getAutoRevokeLiveData().getValue());
if (mIsFirstLoad) {
logAppPermissionGroupsFragmentView();
mIsFirstLoad = false;
}
}
private void addAutoRevokePreferences(PreferenceScreen screen) {
Context context = screen.getPreferenceManager().getContext();
PreferenceCategory autoRevokeCategory = new PreferenceCategory(context);
autoRevokeCategory.setKey(AUTO_REVOKE_CATEGORY_KEY);
screen.addPreference(autoRevokeCategory);
SwitchPreference autoRevokeSwitch = new SwitchPreference(context);
autoRevokeSwitch.setOnPreferenceClickListener((preference) -> {
mViewModel.setAutoRevoke(autoRevokeSwitch.isChecked());
return true;
});
autoRevokeSwitch.setTitle(isHibernationEnabled() ? R.string.unused_apps_label
: R.string.auto_revoke_label);
autoRevokeSwitch.setKey(AUTO_REVOKE_SWITCH_KEY);
autoRevokeCategory.addPreference(autoRevokeSwitch);
Preference autoRevokeSummary = SdkLevel.isAtLeastS() ? new FooterPreference(context)
: new Preference(context);
autoRevokeSummary.setIcon(Utils.applyTint(getActivity(), R.drawable.ic_info_outline,
android.R.attr.colorControlNormal));
autoRevokeSummary.setKey(AUTO_REVOKE_SUMMARY_KEY);
if (isHibernationEnabled()) {
autoRevokeCategory.setTitle(R.string.unused_apps);
}
autoRevokeCategory.addPreference(autoRevokeSummary);
}
private void setAutoRevokeToggleState(HibernationSettingState state) {
if (state == null || !mViewModel.getPackagePermGroupsLiveData().isInitialized()
|| getPreferenceScreen() == null || getListView() == null || getView() == null) {
return;
}
PreferenceCategory autoRevokeCategory = getPreferenceScreen()
.findPreference(AUTO_REVOKE_CATEGORY_KEY);
SwitchPreference autoRevokeSwitch = autoRevokeCategory.findPreference(
AUTO_REVOKE_SWITCH_KEY);
Preference autoRevokeSummary = autoRevokeCategory.findPreference(
AUTO_REVOKE_SUMMARY_KEY);
if (!state.isEnabledGlobal() || state.getRevocableGroupNames().isEmpty()) {
autoRevokeCategory.setVisible(false);
autoRevokeSwitch.setVisible(false);
autoRevokeSummary.setVisible(false);
return;
}
autoRevokeCategory.setVisible(true);
autoRevokeSwitch.setVisible(true);
autoRevokeSummary.setVisible(true);
autoRevokeSwitch.setChecked(state.isEnabledForApp());
List<String> groupLabels = new ArrayList<>();
for (String groupName : state.getRevocableGroupNames()) {
PreferenceCategory category = getPreferenceScreen().findPreference(
Category.ALLOWED.getCategoryName());
Preference pref = category.findPreference(groupName);
if (pref != null) {
groupLabels.add(pref.getTitle().toString());
}
}
groupLabels.sort(mCollator);
if (groupLabels.isEmpty()) {
autoRevokeSummary.setSummary(R.string.auto_revoke_summary);
} else {
autoRevokeSummary.setSummary(getString(R.string.auto_revoke_summary_with_permissions,
ListFormatter.getInstance().format(groupLabels)));
}
}
private int comparePreferences(Preference lhs, Preference rhs) {
String additionalTitle = lhs.getContext().getString(R.string.additional_permissions);
if (lhs.getTitle().equals(additionalTitle)) {
return 1;
} else if (rhs.getTitle().equals(additionalTitle)) {
return -1;
}
return mCollator.compare(lhs.getTitle().toString(),
rhs.getTitle().toString());
}
private Preference setUpCustomPermissionsScreen(Context context, int count, String category) {
final Preference extraPerms = new Preference(context);
extraPerms.setIcon(Utils.applyTint(getActivity(), R.drawable.ic_toc,
android.R.attr.colorControlNormal));
extraPerms.setTitle(R.string.additional_permissions);
extraPerms.setKey(extraPerms.getTitle() + category);
extraPerms.setOnPreferenceClickListener(preference -> {
mViewModel.showExtraPerms(this, AppPermissionGroupsFragment.createArgs(
mPackageName, mUser, getArguments().getLong(EXTRA_SESSION_ID), false));
return true;
});
extraPerms.setSummary(getResources().getQuantityString(
R.plurals.additional_permissions_more, count, count));
return extraPerms;
}
private void setNoPermissionPreference(PreferenceCategory category, @StringRes int stringId,
Context context) {
Preference empty = new Preference(context);
empty.setKey(getString(stringId));
empty.setTitle(empty.getKey());
empty.setSelectable(false);
category.addPreference(empty);
}
private void logAppPermissionGroupsFragmentView() {
Context context = getPreferenceManager().getContext();
if (context == null) {
return;
}
String permissionSubtitleOnlyInForeground =
context.getString(R.string.permission_subtitle_only_in_foreground);
long sessionId = getArguments().getLong(EXTRA_SESSION_ID, INVALID_SESSION_ID);
long viewId = new Random().nextLong();
PreferenceCategory allowed = findPreference(Category.ALLOWED.getCategoryName());
int numAllowed = allowed.getPreferenceCount();
for (int i = 0; i < numAllowed; i++) {
Preference preference = allowed.getPreference(i);
if (preference.getTitle().equals(getString(R.string.no_permissions_allowed))) {
// R.string.no_permission_allowed was added to PreferenceCategory
continue;
}
int category = APP_PERMISSIONS_FRAGMENT_VIEWED__CATEGORY__ALLOWED;
if (preference.getSummary() != null
&& permissionSubtitleOnlyInForeground.contentEquals(preference.getSummary())) {
category = APP_PERMISSIONS_FRAGMENT_VIEWED__CATEGORY__ALLOWED_FOREGROUND;
}
logAppPermissionsFragmentViewEntry(sessionId, viewId, preference.getKey(),
category);
}
PreferenceCategory denied = findPreference(Category.DENIED.getCategoryName());
int numDenied = denied.getPreferenceCount();
for (int i = 0; i < numDenied; i++) {
Preference preference = denied.getPreference(i);
if (preference.getTitle().equals(getString(R.string.no_permissions_denied))) {
// R.string.no_permission_denied was added to PreferenceCategory
continue;
}
logAppPermissionsFragmentViewEntry(sessionId, viewId, preference.getKey(),
APP_PERMISSIONS_FRAGMENT_VIEWED__CATEGORY__DENIED);
}
}
private void logAppPermissionsFragmentViewEntry(
long sessionId, long viewId, String permissionGroupName, int category) {
Integer uid = KotlinUtils.INSTANCE.getPackageUid(getActivity().getApplication(),
mPackageName, mUser);
if (uid == null) {
return;
}
PermissionControllerStatsLog.write(APP_PERMISSIONS_FRAGMENT_VIEWED, sessionId, viewId,
permissionGroupName, uid, mPackageName, category);
Log.v(LOG_TAG, "AppPermissionFragment view logged with sessionId=" + sessionId + " viewId="
+ viewId + " permissionGroupName=" + permissionGroupName + " uid="
+ uid + " packageName="
+ mPackageName + " category=" + category);
}
}