• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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