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.location; 18 19 import android.car.drivingstate.CarUxRestrictions; 20 import android.content.BroadcastReceiver; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.content.IntentFilter; 24 import android.location.LocationManager; 25 26 import androidx.preference.PreferenceCategory; 27 28 import com.android.car.settings.R; 29 import com.android.car.settings.common.FragmentController; 30 import com.android.car.settings.common.PreferenceController; 31 import com.android.car.ui.preference.CarUiPreference; 32 import com.android.internal.annotations.VisibleForTesting; 33 import com.android.settingslib.applications.RecentAppOpsAccess; 34 35 import java.util.HashSet; 36 import java.util.List; 37 import java.util.Set; 38 39 /** 40 * This controller displays a list of apps that recently access the location. Driver assistance apps 41 * are also included. 42 */ 43 public class LocationRecentAccessesPreferenceController 44 extends PreferenceController<PreferenceCategory> { 45 46 private final LocationManager mLocationManager; 47 private final BroadcastReceiver mAdasReceiver = 48 new BroadcastReceiver() { 49 @Override 50 public void onReceive(Context context, Intent intent) { 51 refreshUi(); 52 } 53 }; 54 private final BroadcastReceiver mLocationReceiver = 55 new BroadcastReceiver() { 56 @Override 57 public void onReceive(Context context, Intent intent) { 58 refreshUi(); 59 } 60 }; 61 62 private static final IntentFilter INTENT_FILTER_ADAS_GNSS_ENABLED_CHANGED = 63 new IntentFilter(LocationManager.ACTION_ADAS_GNSS_ENABLED_CHANGED); 64 65 private static final IntentFilter INTENT_FILTER_LOCATION_MODE_CHANGED = 66 new IntentFilter(LocationManager.MODE_CHANGED_ACTION); 67 68 private final Set<CarUiPreference> mAddedPreferences = new HashSet<>(); 69 70 private final RecentAppOpsAccess mRecentLocationAccesses; 71 private final int mRecentAppsMaxCount; 72 LocationRecentAccessesPreferenceController( Context context, String preferenceKey, FragmentController fragmentController, CarUxRestrictions uxRestrictions)73 public LocationRecentAccessesPreferenceController( 74 Context context, 75 String preferenceKey, 76 FragmentController fragmentController, 77 CarUxRestrictions uxRestrictions) { 78 this( 79 context, 80 preferenceKey, 81 fragmentController, 82 uxRestrictions, 83 RecentAppOpsAccess.createForLocation(context), 84 context.getResources().getInteger(R.integer.recent_location_access_apps_list_count), 85 context.getSystemService(LocationManager.class)); 86 } 87 88 @VisibleForTesting LocationRecentAccessesPreferenceController( Context context, String preferenceKey, FragmentController fragmentController, CarUxRestrictions uxRestrictions, RecentAppOpsAccess recentLocationAccesses, int recentAppsMaxCount, LocationManager locationManager)89 LocationRecentAccessesPreferenceController( 90 Context context, 91 String preferenceKey, 92 FragmentController fragmentController, 93 CarUxRestrictions uxRestrictions, 94 RecentAppOpsAccess recentLocationAccesses, 95 int recentAppsMaxCount, 96 LocationManager locationManager) { 97 super(context, preferenceKey, fragmentController, uxRestrictions); 98 mRecentLocationAccesses = recentLocationAccesses; 99 mRecentAppsMaxCount = recentAppsMaxCount; 100 mLocationManager = locationManager; 101 } 102 103 @Override getPreferenceType()104 protected Class<PreferenceCategory> getPreferenceType() { 105 return PreferenceCategory.class; 106 } 107 108 @Override onStartInternal()109 protected void onStartInternal() { 110 getContext().registerReceiver(mAdasReceiver, INTENT_FILTER_ADAS_GNSS_ENABLED_CHANGED); 111 getContext().registerReceiver(mLocationReceiver, INTENT_FILTER_LOCATION_MODE_CHANGED); 112 } 113 114 @Override onStopInternal()115 protected void onStopInternal() { 116 getContext().unregisterReceiver(mAdasReceiver); 117 getContext().unregisterReceiver(mLocationReceiver); 118 } 119 120 @Override updateState(PreferenceCategory preference)121 public void updateState(PreferenceCategory preference) { 122 super.updateState(preference); 123 124 if (!mLocationManager.isLocationEnabled() 125 && !mLocationManager.isAdasGnssLocationEnabled()) { 126 getPreference().setVisible(false); 127 return; 128 } 129 getPreference().setVisible(true); 130 updateUi(loadData()); 131 } 132 loadData()133 private List<RecentAppOpsAccess.Access> loadData() { 134 return mRecentLocationAccesses.getAppListSorted(/* showSystem= */ false); 135 } 136 hasAtLeastOneRecentAppAccess()137 private boolean hasAtLeastOneRecentAppAccess() { 138 return !mRecentLocationAccesses.getAppListSorted(/* showSystem= */ true).isEmpty(); 139 } 140 updateUi(List<RecentAppOpsAccess.Access> sortedRecentLocationAccesses)141 private void updateUi(List<RecentAppOpsAccess.Access> sortedRecentLocationAccesses) { 142 // remove any already added preferences 143 for (CarUiPreference addedPreference : mAddedPreferences) { 144 getPreference().removePreference(addedPreference); 145 } 146 mAddedPreferences.clear(); 147 148 if (sortedRecentLocationAccesses.isEmpty()) { 149 CarUiPreference emptyPreference = createNoRecentAccessPreference(); 150 getPreference().addPreference(emptyPreference); 151 mAddedPreferences.add(emptyPreference); 152 } else { 153 int count = Math.min(sortedRecentLocationAccesses.size(), mRecentAppsMaxCount); 154 for (int i = 0; i < count; i++) { 155 RecentAppOpsAccess.Access request = sortedRecentLocationAccesses.get(i); 156 CarUiPreference appPreference = 157 LocationRecentAccessUtil.createAppPreference(getContext(), request); 158 getPreference().addPreference(appPreference); 159 mAddedPreferences.add(appPreference); 160 } 161 } 162 163 if (hasAtLeastOneRecentAppAccess()) { 164 CarUiPreference viewAllPreference = createViewAllPreference(); 165 getPreference().addPreference(viewAllPreference); 166 mAddedPreferences.add(viewAllPreference); 167 } 168 } 169 createNoRecentAccessPreference()170 private CarUiPreference createNoRecentAccessPreference() { 171 CarUiPreference preference = new CarUiPreference(getContext()); 172 preference.setTitle(R.string.location_no_recent_access); 173 preference.setSelectable(false); 174 return preference; 175 } 176 createViewAllPreference()177 private CarUiPreference createViewAllPreference() { 178 CarUiPreference preference = new CarUiPreference(getContext()); 179 preference.setTitle(R.string.location_settings_recently_accessed_view_all_title); 180 preference.setIcon(R.drawable.ic_apps); 181 preference.setOnPreferenceClickListener( 182 p -> { 183 getFragmentController() 184 .launchFragment(new LocationRecentAccessViewAllFragment()); 185 return true; 186 }); 187 return preference; 188 } 189 } 190