1 /* 2 * Copyright (C) 2015 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 com.android.permissioncontroller.Constants.EXTRA_SESSION_ID; 19 import static com.android.permissioncontroller.Constants.INVALID_SESSION_ID; 20 import static com.android.permissioncontroller.permission.ui.Category.ALLOWED; 21 import static com.android.permissioncontroller.permission.ui.Category.ALLOWED_FOREGROUND; 22 import static com.android.permissioncontroller.permission.ui.Category.ASK; 23 import static com.android.permissioncontroller.permission.ui.Category.DENIED; 24 import static com.android.permissioncontroller.permission.ui.Category.STORAGE_FOOTER; 25 import static com.android.permissioncontroller.permission.ui.handheld.UtilsKt.pressBack; 26 27 import android.Manifest; 28 import android.app.ActionBar; 29 import android.content.Context; 30 import android.content.Intent; 31 import android.graphics.drawable.Drawable; 32 import android.os.Build; 33 import android.os.Bundle; 34 import android.os.Handler; 35 import android.os.Looper; 36 import android.os.UserHandle; 37 import android.os.UserManager; 38 import android.provider.Settings; 39 import android.safetycenter.SafetyCenterManager; 40 import android.util.ArrayMap; 41 import android.view.Menu; 42 import android.view.MenuInflater; 43 import android.view.MenuItem; 44 import android.view.View; 45 46 import androidx.annotation.NonNull; 47 import androidx.annotation.RequiresApi; 48 import androidx.lifecycle.ViewModelProvider; 49 import androidx.preference.Preference; 50 import androidx.preference.PreferenceCategory; 51 import androidx.preference.PreferenceScreen; 52 53 import com.android.modules.utils.build.SdkLevel; 54 import com.android.permissioncontroller.R; 55 import com.android.permissioncontroller.permission.model.v31.AppPermissionUsage; 56 import com.android.permissioncontroller.permission.model.v31.PermissionUsages; 57 import com.android.permissioncontroller.permission.ui.Category; 58 import com.android.permissioncontroller.permission.ui.handheld.v31.CardViewPreference; 59 import com.android.permissioncontroller.permission.ui.model.PermissionAppsViewModel; 60 import com.android.permissioncontroller.permission.ui.model.PermissionAppsViewModelFactory; 61 import com.android.permissioncontroller.permission.utils.KotlinUtils; 62 import com.android.permissioncontroller.permission.utils.Utils; 63 import com.android.settingslib.HelpUtils; 64 import com.android.settingslib.utils.applications.AppUtils; 65 import com.android.settingslib.widget.FooterPreference; 66 67 import kotlin.Pair; 68 import kotlin.Triple; 69 70 import java.text.Collator; 71 import java.util.ArrayList; 72 import java.util.List; 73 import java.util.Map; 74 import java.util.Random; 75 76 /** 77 * Show and manage apps which request a single permission group. 78 * 79 * <p>Shows a list of apps which request at least on permission of this group. 80 */ 81 public final class PermissionAppsFragment extends SettingsWithLargeHeader implements 82 PermissionUsages.PermissionsUsagesChangeCallback { 83 84 private static final String KEY_SHOW_SYSTEM_PREFS = "_showSystem"; 85 private static final String CREATION_LOGGED_SYSTEM_PREFS = "_creationLogged"; 86 private static final String KEY_FOOTER = "_footer"; 87 private static final String KEY_EMPTY = "_empty"; 88 private static final String LOG_TAG = "PermissionAppsFragment"; 89 private static final String STORAGE_ALLOWED_FULL = "allowed_storage_full"; 90 private static final String STORAGE_ALLOWED_SCOPED = "allowed_storage_scoped"; 91 private static final String BLOCKED_SENSOR_PREF_KEY = "sensor_card"; 92 private static final String STORAGE_FOOTER_PREFERENCE_KEY = "storage_footer_preference"; 93 private static final int SHOW_LOAD_DELAY_MS = 200; 94 95 private static final String PRIVACY_CONTROLS_ACTION = "android.settings.PRIVACY_CONTROLS"; 96 97 /** 98 * Create a bundle with the arguments needed by this fragment 99 * 100 * @param permGroupName The name of the permission group 101 * @param sessionId The current session ID 102 * @return A bundle with all of the args placed 103 */ createArgs(String permGroupName, long sessionId)104 public static Bundle createArgs(String permGroupName, long sessionId) { 105 Bundle arguments = new Bundle(); 106 arguments.putString(Intent.EXTRA_PERMISSION_GROUP_NAME, permGroupName); 107 arguments.putLong(EXTRA_SESSION_ID, sessionId); 108 return arguments; 109 } 110 111 private MenuItem mShowSystemMenu; 112 private MenuItem mHideSystemMenu; 113 private String mPermGroupName; 114 private Collator mCollator; 115 private PermissionAppsViewModel mViewModel; 116 private PermissionUsages mPermissionUsages; 117 private List<AppPermissionUsage> mAppPermissionUsages = new ArrayList<>(); 118 private Boolean mSensorStatus; 119 private UserManager mUserManager; 120 121 @Override onCreate(Bundle savedInstanceState)122 public void onCreate(Bundle savedInstanceState) { 123 super.onCreate(savedInstanceState); 124 125 mPermGroupName = getArguments().getString(Intent.EXTRA_PERMISSION_GROUP_NAME); 126 if (mPermGroupName == null) { 127 mPermGroupName = getArguments().getString(Intent.EXTRA_PERMISSION_NAME); 128 } 129 130 mCollator = Collator.getInstance( 131 getContext().getResources().getConfiguration().getLocales().get(0)); 132 133 PermissionAppsViewModelFactory factory = 134 new PermissionAppsViewModelFactory(getActivity().getApplication(), mPermGroupName, 135 this, new Bundle()); 136 mViewModel = new ViewModelProvider(this, factory).get(PermissionAppsViewModel.class); 137 138 mViewModel.getCategorizedAppsLiveData().observe(this, this::onPackagesLoaded); 139 mViewModel.getShouldShowSystemLiveData().observe(this, this::updateMenu); 140 mViewModel.getHasSystemAppsLiveData().observe(this, (Boolean hasSystem) -> 141 getActivity().invalidateOptionsMenu()); 142 143 if (!mViewModel.arePackagesLoaded()) { 144 Handler handler = new Handler(Looper.getMainLooper()); 145 handler.postDelayed(() -> { 146 if (!mViewModel.arePackagesLoaded()) { 147 setLoading(true /* loading */, false /* animate */); 148 } 149 }, SHOW_LOAD_DELAY_MS); 150 } 151 152 setHasOptionsMenu(true); 153 final ActionBar ab = getActivity().getActionBar(); 154 if (ab != null) { 155 ab.setDisplayHomeAsUpEnabled(true); 156 } 157 158 // If the build type is below S, the app ops for permission usage can't be found. Thus, we 159 // shouldn't load permission usages, for them. 160 if (SdkLevel.isAtLeastS()) { 161 Context context = getPreferenceManager().getContext(); 162 mPermissionUsages = new PermissionUsages(context); 163 164 long filterTimeBeginMillis = mViewModel.getFilterTimeBeginMillis(); 165 mPermissionUsages.load(null, null, filterTimeBeginMillis, Long.MAX_VALUE, 166 PermissionUsages.USAGE_FLAG_LAST, getActivity().getLoaderManager(), 167 false, false, this, false); 168 169 if (Utils.shouldDisplayCardIfBlocked(mPermGroupName)) { 170 mViewModel.getSensorStatusLiveData().observe(this, this::setSensorStatus); 171 } 172 } 173 174 mUserManager = Utils.getSystemServiceSafe(getContext(), UserManager.class); 175 } 176 177 @Override 178 @RequiresApi(Build.VERSION_CODES.S) onPermissionUsagesChanged()179 public void onPermissionUsagesChanged() { 180 if (mPermissionUsages.getUsages().isEmpty()) { 181 return; 182 } 183 if (getContext() == null) { 184 // Async result has come in after our context is gone. 185 return; 186 } 187 188 mAppPermissionUsages = new ArrayList<>(mPermissionUsages.getUsages()); 189 onPackagesLoaded(mViewModel.getCategorizedAppsLiveData().getValue()); 190 } 191 192 @Override onCreateOptionsMenu(Menu menu, MenuInflater inflater)193 public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 194 super.onCreateOptionsMenu(menu, inflater); 195 196 if (mViewModel.getHasSystemAppsLiveData().getValue()) { 197 mShowSystemMenu = menu.add(Menu.NONE, MENU_SHOW_SYSTEM, Menu.NONE, 198 R.string.menu_show_system); 199 mHideSystemMenu = menu.add(Menu.NONE, MENU_HIDE_SYSTEM, Menu.NONE, 200 R.string.menu_hide_system); 201 updateMenu(mViewModel.getShouldShowSystemLiveData().getValue()); 202 } 203 204 if (!SdkLevel.isAtLeastS()) { 205 HelpUtils.prepareHelpMenuItem(getActivity(), menu, R.string.help_app_permissions, 206 getClass().getName()); 207 } 208 } 209 210 @Override onOptionsItemSelected(MenuItem item)211 public boolean onOptionsItemSelected(MenuItem item) { 212 switch (item.getItemId()) { 213 case android.R.id.home: 214 mViewModel.updateShowSystem(false); 215 pressBack(this); 216 return true; 217 case MENU_SHOW_SYSTEM: 218 case MENU_HIDE_SYSTEM: 219 mViewModel.updateShowSystem(item.getItemId() == MENU_SHOW_SYSTEM); 220 break; 221 } 222 return super.onOptionsItemSelected(item); 223 } 224 updateMenu(Boolean showSystem)225 private void updateMenu(Boolean showSystem) { 226 if (showSystem == null) { 227 showSystem = false; 228 } 229 if (mShowSystemMenu != null && mHideSystemMenu != null) { 230 mShowSystemMenu.setVisible(!showSystem); 231 mHideSystemMenu.setVisible(showSystem); 232 } 233 } 234 235 @RequiresApi(Build.VERSION_CODES.S) setSensorStatus(Boolean sensorStatus)236 private void setSensorStatus(Boolean sensorStatus) { 237 mSensorStatus = sensorStatus; 238 displaySensorCard(); 239 } 240 241 @RequiresApi(Build.VERSION_CODES.S) displaySensorCard()242 private void displaySensorCard() { 243 if (Utils.shouldDisplayCardIfBlocked(mPermGroupName)) { 244 if (mSensorStatus) { 245 setSensorCard(); 246 } else { 247 removeSensorCard(); 248 } 249 } 250 } 251 252 @RequiresApi(Build.VERSION_CODES.S) setSensorCard()253 private void setSensorCard() { 254 CardViewPreference sensorCard = findPreference(BLOCKED_SENSOR_PREF_KEY); 255 if (sensorCard == null) { 256 sensorCard = createSensorCard(); 257 ensurePreferenceScreen(); 258 getPreferenceScreen().addPreference(sensorCard); 259 } 260 sensorCard.setVisible(true); 261 } 262 ensurePreferenceScreen()263 private void ensurePreferenceScreen() { 264 // Check if preference screen has been already loaded 265 if (getPreferenceScreen() != null) { 266 return; 267 } 268 boolean isStorageAndLessThanT = !SdkLevel.isAtLeastT() 269 && mPermGroupName.equals(Manifest.permission_group.STORAGE); 270 if (isStorageAndLessThanT) { 271 addPreferencesFromResource(R.xml.allowed_denied_storage); 272 } else { 273 addPreferencesFromResource(R.xml.allowed_denied); 274 } 275 // Hide allowed foreground label by default, to avoid briefly showing it before updating 276 findPreference(ALLOWED_FOREGROUND.getCategoryName()).setVisible(false); 277 } 278 279 @RequiresApi(Build.VERSION_CODES.TIRAMISU) getPrivacyControlsIntent()280 private String getPrivacyControlsIntent() { 281 Context context = getPreferenceManager().getContext(); 282 SafetyCenterManager safetyCenterManager = 283 context.getSystemService(SafetyCenterManager.class); 284 if (safetyCenterManager.isSafetyCenterEnabled()) { 285 return PRIVACY_CONTROLS_ACTION; 286 } else { 287 return Settings.ACTION_PRIVACY_SETTINGS; 288 } 289 } 290 291 @RequiresApi(Build.VERSION_CODES.S) createSensorCard()292 private CardViewPreference createSensorCard() { 293 boolean isLocation = Manifest.permission_group.LOCATION.equals(mPermGroupName); 294 Context context = getPreferenceManager().getContext(); 295 296 String action; 297 if (isLocation) { 298 action = Settings.ACTION_LOCATION_SOURCE_SETTINGS; 299 } else if (SdkLevel.isAtLeastT()) { 300 action = getPrivacyControlsIntent(); 301 } else { 302 action = Settings.ACTION_PRIVACY_SETTINGS; 303 } 304 CardViewPreference sensorCard = new CardViewPreference(context, action); 305 sensorCard.setKey(BLOCKED_SENSOR_PREF_KEY); 306 sensorCard.setIcon(Utils.getBlockedIcon(mPermGroupName)); 307 sensorCard.setTitle(Utils.getBlockedTitle(mPermGroupName)); 308 boolean isMicrophone = Manifest.permission_group.MICROPHONE.equals(mPermGroupName); 309 int cardSummary = 310 isMicrophone ? R.string.blocked_mic_summary : R.string.blocked_sensor_summary; 311 sensorCard.setSummary(context.getString(cardSummary)); 312 sensorCard.setVisible(true); 313 sensorCard.setOrder(-1); 314 return sensorCard; 315 } 316 addStorageFooterSeeAllFilesAccess()317 private void addStorageFooterSeeAllFilesAccess() { 318 PreferenceScreen screen = getPreferenceScreen(); 319 Context context = screen.getPreferenceManager().getContext(); 320 PreferenceCategory preferenceCategory = findPreference(STORAGE_FOOTER.getCategoryName()); 321 Preference existingPreference = findPreference(STORAGE_FOOTER_PREFERENCE_KEY); 322 323 if (preferenceCategory == null || existingPreference != null) { 324 return; 325 } 326 327 FooterPreference preference = new FooterPreference(context); 328 preference.setKey(STORAGE_FOOTER_PREFERENCE_KEY); 329 preference.setIcon(Utils.applyTint(getActivity(), R.drawable.ic_info_outline, 330 android.R.attr.colorControlNormal)); 331 preference.setLearnMoreText(getString(R.string.storage_footer_hyperlink_text)); 332 preference.setLearnMoreAction(v -> { 333 context.startActivity( 334 new Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION)); 335 }); 336 337 preferenceCategory.addPreference(preference); 338 } 339 340 @RequiresApi(Build.VERSION_CODES.S) removeSensorCard()341 private void removeSensorCard() { 342 CardViewPreference sensorCard = findPreference(BLOCKED_SENSOR_PREF_KEY); 343 if (sensorCard != null) { 344 sensorCard.setVisible(false); 345 } 346 } 347 348 @Override onViewCreated(View view, Bundle savedInstanceState)349 public void onViewCreated(View view, Bundle savedInstanceState) { 350 super.onViewCreated(view, savedInstanceState); 351 bindUi(this, mPermGroupName); 352 } 353 bindUi(SettingsWithLargeHeader fragment, @NonNull String groupName)354 private static void bindUi(SettingsWithLargeHeader fragment, @NonNull String groupName) { 355 Context context = fragment.getContext(); 356 if (context == null || fragment.getActivity() == null) { 357 return; 358 } 359 Drawable icon = KotlinUtils.INSTANCE.getPermGroupIcon(context, groupName); 360 361 CharSequence label = KotlinUtils.INSTANCE.getPermGroupLabel(context, groupName); 362 CharSequence description = KotlinUtils.INSTANCE.getPermGroupDescription(context, groupName); 363 364 fragment.setHeader(icon, label, null, null, true); 365 fragment.setSummary(Utils.getPermissionGroupDescriptionString(fragment.getActivity(), 366 groupName, description), null); 367 fragment.getActivity().setTitle(label); 368 } 369 onPackagesLoaded(Map<Category, List<Pair<String, UserHandle>>> categories)370 private void onPackagesLoaded(Map<Category, List<Pair<String, UserHandle>>> categories) { 371 boolean isStorageAndLessThanT = !SdkLevel.isAtLeastT() 372 && mPermGroupName.equals(Manifest.permission_group.STORAGE); 373 ensurePreferenceScreen(); 374 Context context = getPreferenceManager().getContext(); 375 376 if (context == null || getActivity() == null || categories == null) { 377 return; 378 } 379 380 Map<String, Preference> existingPrefs = new ArrayMap<>(); 381 382 for (int i = 0; i < getPreferenceScreen().getPreferenceCount(); i++) { 383 Preference pref = getPreferenceScreen().getPreference(i); 384 if (BLOCKED_SENSOR_PREF_KEY.equals(pref.getKey())) { 385 continue; 386 } 387 PreferenceCategory category = (PreferenceCategory) pref; 388 category.setOrderingAsAdded(true); 389 int numPreferences = category.getPreferenceCount(); 390 for (int j = 0; j < numPreferences; j++) { 391 Preference preference = category.getPreference(j); 392 existingPrefs.put(preference.getKey(), preference); 393 } 394 category.removeAll(); 395 } 396 397 long viewIdForLogging = new Random().nextLong(); 398 long sessionId = getArguments().getLong(EXTRA_SESSION_ID, INVALID_SESSION_ID); 399 400 Boolean showAlways = mViewModel.getShowAllowAlwaysStringLiveData().getValue(); 401 if (!isStorageAndLessThanT) { 402 if (showAlways != null && showAlways) { 403 findPreference(ALLOWED.getCategoryName()).setTitle(R.string.allowed_always_header); 404 } else { 405 findPreference(ALLOWED.getCategoryName()).setTitle(R.string.allowed_header); 406 } 407 } 408 409 // A mapping of user + packageName to their last access timestamps for the permission group. 410 Map<String, Long> groupUsageLastAccessTime = 411 mViewModel.extractGroupUsageLastAccessTime(mAppPermissionUsages); 412 413 for (Category grantCategory : categories.keySet()) { 414 List<Pair<String, UserHandle>> packages = categories.get(grantCategory); 415 PreferenceCategory category = findPreference(grantCategory.getCategoryName()); 416 417 418 // If this category is empty, and this isn't the "allowed" category of the storage 419 // permission, set up the empty preference. 420 if (packages.size() == 0 421 && (!isStorageAndLessThanT || !grantCategory.equals(ALLOWED))) { 422 Preference empty = new Preference(context); 423 empty.setSelectable(false); 424 empty.setKey(category.getKey() + KEY_EMPTY); 425 if (grantCategory.equals(ALLOWED)) { 426 empty.setTitle(getString(R.string.no_apps_allowed)); 427 } else if (grantCategory.equals(ALLOWED_FOREGROUND)) { 428 category.setVisible(false); 429 } else if (grantCategory.equals(ASK)) { 430 category.setVisible(false); 431 } else { 432 empty.setTitle(getString(R.string.no_apps_denied)); 433 } 434 category.addPreference(empty); 435 continue; 436 } else if (grantCategory.equals(ALLOWED_FOREGROUND)) { 437 category.setVisible(true); 438 } else if (grantCategory.equals(ASK)) { 439 category.setVisible(true); 440 } 441 442 for (Pair<String, UserHandle> packageUserLabel : packages) { 443 if (!Utils.shouldShowInSettings(packageUserLabel.getSecond(), mUserManager)) { 444 continue; 445 } 446 String packageName = packageUserLabel.getFirst(); 447 UserHandle user = packageUserLabel.getSecond(); 448 449 String key = user + packageName; 450 451 Long lastAccessTime = groupUsageLastAccessTime.get(key); 452 Triple<String, Integer, String> summaryTimestamp = Utils 453 .getPermissionLastAccessSummaryTimestamp( 454 lastAccessTime, context, mPermGroupName); 455 456 if (isStorageAndLessThanT && grantCategory.equals(ALLOWED)) { 457 category = mViewModel.packageHasFullStorage(packageName, user) 458 ? findPreference(STORAGE_ALLOWED_FULL) 459 : findPreference(STORAGE_ALLOWED_SCOPED); 460 } 461 462 Preference existingPref = existingPrefs.get(key); 463 if (existingPref != null) { 464 updatePreferenceSummary(existingPref, summaryTimestamp); 465 category.addPreference(existingPref); 466 continue; 467 } 468 469 SmartIconLoadPackagePermissionPreference pref = 470 new SmartIconLoadPackagePermissionPreference(getActivity().getApplication(), 471 packageName, user, context); 472 pref.setKey(key); 473 pref.setTitle(KotlinUtils.INSTANCE.getPackageLabel(getActivity().getApplication(), 474 packageName, user)); 475 pref.setOnPreferenceClickListener((Preference p) -> { 476 mViewModel.navigateToAppPermission(this, packageName, user, 477 AppPermissionFragment.createArgs(packageName, null, mPermGroupName, 478 user, getClass().getName(), sessionId, 479 grantCategory.getCategoryName())); 480 return true; 481 }); 482 pref.setTitleContentDescription(AppUtils.getAppContentDescription(context, 483 packageName, user.getIdentifier())); 484 485 updatePreferenceSummary(pref, summaryTimestamp); 486 487 category.addPreference(pref); 488 if (!mViewModel.getCreationLogged()) { 489 logPermissionAppsFragmentCreated(packageName, user, viewIdForLogging, 490 grantCategory.equals(ALLOWED), grantCategory.equals(ALLOWED_FOREGROUND), 491 grantCategory.equals(DENIED)); 492 } 493 } 494 495 if (isStorageAndLessThanT && grantCategory.equals(ALLOWED)) { 496 PreferenceCategory full = findPreference(STORAGE_ALLOWED_FULL); 497 PreferenceCategory scoped = findPreference(STORAGE_ALLOWED_SCOPED); 498 if (full.getPreferenceCount() == 0) { 499 Preference empty = new Preference(context); 500 empty.setSelectable(false); 501 empty.setKey(STORAGE_ALLOWED_FULL + KEY_EMPTY); 502 empty.setTitle(getString(R.string.no_apps_allowed_full)); 503 full.addPreference(empty); 504 } 505 506 if (scoped.getPreferenceCount() == 0) { 507 Preference empty = new Preference(context); 508 empty.setSelectable(false); 509 empty.setKey(STORAGE_ALLOWED_FULL + KEY_EMPTY); 510 empty.setTitle(getString(R.string.no_apps_allowed_scoped)); 511 scoped.addPreference(empty); 512 } 513 KotlinUtils.INSTANCE.sortPreferenceGroup(full, this::comparePreference, false); 514 KotlinUtils.INSTANCE.sortPreferenceGroup(scoped, this::comparePreference, false); 515 } else { 516 KotlinUtils.INSTANCE.sortPreferenceGroup(category, this::comparePreference, false); 517 } 518 } 519 520 if (SdkLevel.isAtLeastT() && Manifest.permission_group.STORAGE.equals(mPermGroupName)) { 521 addStorageFooterSeeAllFilesAccess(); 522 } else { 523 // Hide storage footer category 524 PreferenceCategory storageFooterPreferenceCategory = 525 findPreference(STORAGE_FOOTER.getCategoryName()); 526 if (storageFooterPreferenceCategory != null) { 527 storageFooterPreferenceCategory.setVisible(false); 528 } 529 } 530 531 mViewModel.setCreationLogged(true); 532 533 setLoading(false /* loading */, true /* animate */); 534 } 535 updatePreferenceSummary(Preference preference, Triple<String, Integer, String> summaryTimestamp)536 private void updatePreferenceSummary(Preference preference, 537 Triple<String, Integer, String> summaryTimestamp) { 538 String summary = mViewModel.getPreferenceSummary(getResources(), summaryTimestamp); 539 if (!summary.isEmpty()) { 540 preference.setSummary(summary); 541 } 542 } 543 544 comparePreference(Preference lhs, Preference rhs)545 private int comparePreference(Preference lhs, Preference rhs) { 546 int result = mCollator.compare(lhs.getTitle().toString(), 547 rhs.getTitle().toString()); 548 if (result == 0) { 549 result = lhs.getKey().compareTo(rhs.getKey()); 550 } 551 return result; 552 } 553 logPermissionAppsFragmentCreated(String packageName, UserHandle user, long viewId, boolean isAllowed, boolean isAllowedForeground, boolean isDenied)554 private void logPermissionAppsFragmentCreated(String packageName, UserHandle user, long viewId, 555 boolean isAllowed, boolean isAllowedForeground, boolean isDenied) { 556 long sessionId = getArguments().getLong(EXTRA_SESSION_ID, 0); 557 mViewModel.logPermissionAppsFragmentCreated(packageName, user, viewId, isAllowed, 558 isAllowedForeground, isDenied, sessionId, getActivity().getApplication(), 559 mPermGroupName, LOG_TAG); 560 } 561 } 562