1 /* 2 * Copyright (C) 2018 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.Context; 21 import android.content.pm.PackageManager; 22 23 import androidx.annotation.VisibleForTesting; 24 import androidx.preference.Preference; 25 import androidx.preference.PreferenceGroup; 26 27 import com.android.car.settings.R; 28 import com.android.car.settings.applications.ApplicationDetailsFragment; 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.settingslib.location.RecentLocationApps; 33 import com.android.settingslib.location.RecentLocationApps.Request; 34 35 import java.util.List; 36 37 /** 38 * Displays all apps that have requested location recently. 39 */ 40 public class RecentLocationRequestsPreferenceController extends 41 PreferenceController<PreferenceGroup> { 42 private final PackageManager mPackageManager; 43 private RecentLocationApps mRecentLocationApps; 44 // This list will always be sorted by most recent first. 45 private List<Request> mRecentLocationRequests; 46 RecentLocationRequestsPreferenceController(Context context, String preferenceKey, FragmentController fragmentController, CarUxRestrictions uxRestrictions)47 public RecentLocationRequestsPreferenceController(Context context, String preferenceKey, 48 FragmentController fragmentController, CarUxRestrictions uxRestrictions) { 49 super(context, preferenceKey, fragmentController, uxRestrictions); 50 mRecentLocationApps = new RecentLocationApps(context); 51 mPackageManager = context.getPackageManager(); 52 } 53 54 @VisibleForTesting setRecentLocationApps(RecentLocationApps apps)55 void setRecentLocationApps(RecentLocationApps apps) { 56 mRecentLocationApps = apps; 57 } 58 59 @Override getPreferenceType()60 protected Class<PreferenceGroup> getPreferenceType() { 61 return PreferenceGroup.class; 62 } 63 64 @Override updateState(PreferenceGroup group)65 protected void updateState(PreferenceGroup group) { 66 if (mRecentLocationRequests == null) { 67 // First time displaying a list. 68 mRecentLocationRequests = 69 mRecentLocationApps.getAppListSorted(/* showSystemApps= */ true); 70 } else { 71 // If preferences were already added to the screen, get a new list 72 // and only update the displayed app-list if there is a difference. 73 List<Request> newRequests = mRecentLocationApps.getAppListSorted(true); 74 // listsEqual compares by elements' package names only, using List.equals() will 75 // not work because it will always return false since it also compares the time. 76 if (listsEqual(newRequests, mRecentLocationRequests)) { 77 return; 78 } 79 mRecentLocationRequests = newRequests; 80 } 81 if (mRecentLocationRequests.isEmpty()) { 82 CarUiPreference emptyMessagePref = new CarUiPreference(getContext()); 83 emptyMessagePref.setTitle(R.string.location_settings_recent_requests_empty_message); 84 group.addPreference(emptyMessagePref); 85 } else { 86 group.removeAll(); 87 for (Request request : mRecentLocationRequests) { 88 Preference appPref = createPreference(request); 89 group.addPreference(appPref); 90 } 91 } 92 } 93 createPreference(Request request)94 private Preference createPreference(Request request) { 95 CarUiPreference pref = new CarUiPreference(getContext()); 96 pref.setSummary(request.contentDescription); 97 pref.setIcon(request.icon); 98 pref.setTitle(request.label); 99 if (isPackageInstalled(request.packageName)) { 100 pref.setOnPreferenceClickListener(p -> { 101 getFragmentController().launchFragment( 102 ApplicationDetailsFragment.getInstance( 103 request.packageName)); 104 return true; 105 }); 106 } 107 return pref; 108 } 109 isPackageInstalled(String packageName)110 private boolean isPackageInstalled(String packageName) { 111 try { 112 mPackageManager.getPackageInfo(packageName, PackageManager.GET_META_DATA); 113 } catch (PackageManager.NameNotFoundException e) { 114 return false; 115 } 116 return true; 117 } 118 119 /** 120 * Compares two {@link Request} lists by the elements' package names. 121 * 122 * @param a The first list. 123 * @param b The second list. 124 * @return {@code true} if both lists have the same elements (by package name) and order. 125 */ listsEqual(List<Request> a, List<Request> b)126 private boolean listsEqual(List<Request> a, List<Request> b) { 127 if (a.size() != b.size()) { 128 return false; 129 } 130 for (int i = 0; i < a.size(); i++) { 131 if (!a.get(i).packageName.equals(b.get(i).packageName)) { 132 return false; 133 } 134 } 135 return true; 136 } 137 } 138