1 /* 2 * Copyright (C) 2022 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.car.settings.privacy; 18 19 import android.car.drivingstate.CarUxRestrictions; 20 import android.content.Context; 21 import android.hardware.SensorPrivacyManager; 22 23 import androidx.preference.PreferenceCategory; 24 25 import com.android.car.settings.R; 26 import com.android.car.settings.common.FragmentController; 27 import com.android.car.ui.preference.CarUiPreference; 28 import com.android.internal.annotations.VisibleForTesting; 29 import com.android.settingslib.applications.RecentAppOpsAccess; 30 31 import java.util.HashSet; 32 import java.util.List; 33 import java.util.Set; 34 35 /** 36 * This controller displays a list of apps that recently access the camera. Only non-system apps 37 * are displayed. 38 */ 39 public class CameraRecentAccessesPreferenceController extends 40 CameraPrivacyBasePreferenceController<PreferenceCategory> { 41 42 private final Set<CarUiPreference> mAddedPreferences = new HashSet<>(); 43 44 private final RecentAppOpsAccess mRecentCameraAccesses; 45 private final int mRecentAppsMaxCount; 46 CameraRecentAccessesPreferenceController(Context context, String preferenceKey, FragmentController fragmentController, CarUxRestrictions uxRestrictions)47 public CameraRecentAccessesPreferenceController(Context context, String preferenceKey, 48 FragmentController fragmentController, CarUxRestrictions uxRestrictions) { 49 this(context, preferenceKey, fragmentController, uxRestrictions, 50 RecentAppOpsAccess.createForCamera(context), 51 context.getResources() 52 .getInteger(R.integer.recent_camera_access_apps_list_count), 53 SensorPrivacyManager.getInstance(context)); 54 } 55 56 57 @VisibleForTesting CameraRecentAccessesPreferenceController(Context context, String preferenceKey, FragmentController fragmentController, CarUxRestrictions uxRestrictions, RecentAppOpsAccess recentCameraAccesses, int recentAppsMaxCount, SensorPrivacyManager sensorPrivacyManager)58 CameraRecentAccessesPreferenceController(Context context, String preferenceKey, 59 FragmentController fragmentController, CarUxRestrictions uxRestrictions, 60 RecentAppOpsAccess recentCameraAccesses, int recentAppsMaxCount, 61 SensorPrivacyManager sensorPrivacyManager) { 62 super(context, preferenceKey, fragmentController, uxRestrictions, sensorPrivacyManager); 63 mRecentCameraAccesses = recentCameraAccesses; 64 mRecentAppsMaxCount = recentAppsMaxCount; 65 } 66 67 68 @Override getPreferenceType()69 protected Class<PreferenceCategory> getPreferenceType() { 70 return PreferenceCategory.class; 71 } 72 73 @Override updateState(PreferenceCategory preference)74 public void updateState(PreferenceCategory preference) { 75 super.updateState(preference); 76 if (getSensorPrivacyManager().isSensorPrivacyEnabled( 77 SensorPrivacyManager.Sensors.CAMERA)) { 78 getPreference().setVisible(false); 79 return; 80 } 81 getPreference().setVisible(true); 82 List<RecentAppOpsAccess.Access> sortedRecentCameraAccesses = loadData(); 83 updateUi(sortedRecentCameraAccesses); 84 } 85 loadData()86 private List<RecentAppOpsAccess.Access> loadData() { 87 return mRecentCameraAccesses.getAppListSorted(/* showSystem= */ false); 88 } 89 hasAtLeastOneRecentAppAccess()90 private boolean hasAtLeastOneRecentAppAccess() { 91 return !mRecentCameraAccesses.getAppListSorted(/* showSystem= */ true).isEmpty(); 92 } 93 updateUi(List<RecentAppOpsAccess.Access> sortedRecentCameraAccesses)94 private void updateUi(List<RecentAppOpsAccess.Access> sortedRecentCameraAccesses) { 95 // remove any already added preferences 96 for (CarUiPreference addedPreference : mAddedPreferences) { 97 getPreference().removePreference(addedPreference); 98 } 99 mAddedPreferences.clear(); 100 101 if (sortedRecentCameraAccesses.isEmpty()) { 102 CarUiPreference emptyPreference = createNoRecentAccessPreference(); 103 getPreference().addPreference(emptyPreference); 104 mAddedPreferences.add(emptyPreference); 105 } else { 106 int count = Math.min(sortedRecentCameraAccesses.size(), mRecentAppsMaxCount); 107 for (int i = 0; i < count; i++) { 108 RecentAppOpsAccess.Access request = sortedRecentCameraAccesses.get(i); 109 CarUiPreference appPreference = CameraRecentAccessUtil.createAppPreference( 110 getContext(), 111 request); 112 getPreference().addPreference(appPreference); 113 mAddedPreferences.add(appPreference); 114 } 115 } 116 117 if (hasAtLeastOneRecentAppAccess()) { 118 CarUiPreference viewAllPreference = createViewAllPreference(); 119 getPreference().addPreference(viewAllPreference); 120 mAddedPreferences.add(viewAllPreference); 121 } 122 } 123 createNoRecentAccessPreference()124 private CarUiPreference createNoRecentAccessPreference() { 125 CarUiPreference preference = new CarUiPreference(getContext()); 126 preference.setTitle(R.string.camera_no_recent_access); 127 preference.setSelectable(false); 128 return preference; 129 } 130 createViewAllPreference()131 private CarUiPreference createViewAllPreference() { 132 CarUiPreference preference = new CarUiPreference(getContext()); 133 preference.setTitle(R.string.camera_settings_recent_requests_view_all_title); 134 preference.setIcon(R.drawable.ic_apps); 135 preference.setOnPreferenceClickListener(p -> { 136 getFragmentController().launchFragment(new CameraRecentAccessViewAllFragment()); 137 return true; 138 }); 139 return preference; 140 } 141 } 142