1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file 5 * except in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the 10 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 11 * KIND, either express or implied. See the License for the specific language governing 12 * permissions and limitations under the License. 13 */ 14 package com.android.settings.location; 15 16 import static java.util.concurrent.TimeUnit.DAYS; 17 18 import android.Manifest; 19 import android.content.Context; 20 import android.content.Intent; 21 import android.icu.text.RelativeDateTimeFormatter; 22 import android.provider.DeviceConfig; 23 import android.view.View; 24 25 import androidx.annotation.VisibleForTesting; 26 import androidx.preference.Preference; 27 import androidx.preference.PreferenceScreen; 28 29 import com.android.settings.R; 30 import com.android.settings.Utils; 31 import com.android.settings.core.PreferenceControllerMixin; 32 import com.android.settingslib.core.AbstractPreferenceController; 33 import com.android.settingslib.location.RecentLocationAccesses; 34 import com.android.settingslib.utils.StringUtil; 35 import com.android.settingslib.widget.AppEntitiesHeaderController; 36 import com.android.settingslib.widget.AppEntityInfo; 37 import com.android.settingslib.widget.LayoutPreference; 38 39 import java.util.List; 40 41 public class RecentLocationAccessPreferenceController extends AbstractPreferenceController 42 implements PreferenceControllerMixin { 43 /** Key for the recent location apps dashboard */ 44 private static final String KEY_APPS_DASHBOARD = "apps_dashboard"; 45 private final RecentLocationAccesses mRecentLocationAccesses; 46 private AppEntitiesHeaderController mController; 47 private static final int MAXIMUM_APP_COUNT = 3; 48 RecentLocationAccessPreferenceController(Context context)49 public RecentLocationAccessPreferenceController(Context context) { 50 this(context, new RecentLocationAccesses(context)); 51 } 52 53 @VisibleForTesting RecentLocationAccessPreferenceController(Context context, RecentLocationAccesses recentAccesses)54 RecentLocationAccessPreferenceController(Context context, 55 RecentLocationAccesses recentAccesses) { 56 super(context); 57 mRecentLocationAccesses = recentAccesses; 58 } 59 60 @Override getPreferenceKey()61 public String getPreferenceKey() { 62 return KEY_APPS_DASHBOARD; 63 } 64 65 @Override isAvailable()66 public boolean isAvailable() { 67 return Boolean.parseBoolean( 68 DeviceConfig.getProperty(DeviceConfig.NAMESPACE_PRIVACY, 69 Utils.PROPERTY_PERMISSIONS_HUB_ENABLED)); 70 } 71 72 @Override displayPreference(PreferenceScreen screen)73 public void displayPreference(PreferenceScreen screen) { 74 super.displayPreference(screen); 75 final LayoutPreference preference = screen.findPreference(KEY_APPS_DASHBOARD); 76 final View view = preference.findViewById(R.id.app_entities_header); 77 mController = AppEntitiesHeaderController.newInstance(mContext, view) 78 .setHeaderTitleRes(R.string.location_category_recent_location_access) 79 .setHeaderDetailsRes(R.string.location_recent_location_access_view_details) 80 .setHeaderEmptyRes(R.string.location_no_recent_accesses) 81 .setHeaderDetailsClickListener((View v) -> { 82 final Intent intent = new Intent(Intent.ACTION_REVIEW_PERMISSION_USAGE); 83 intent.putExtra(Intent.EXTRA_PERMISSION_NAME, 84 Manifest.permission.ACCESS_FINE_LOCATION); 85 intent.putExtra(Intent.EXTRA_DURATION_MILLIS, DAYS.toMillis(1)); 86 mContext.startActivity(intent); 87 }); 88 } 89 90 @Override updateState(Preference preference)91 public void updateState(Preference preference) { 92 updateRecentApps(); 93 } 94 updateRecentApps()95 private void updateRecentApps() { 96 final List<RecentLocationAccesses.Access> recentLocationAccesses = 97 mRecentLocationAccesses.getAppListSorted(); 98 if (recentLocationAccesses.size() > 0) { 99 // Display the top 3 preferences to container in original order. 100 int i = 0; 101 for (; i < Math.min(recentLocationAccesses.size(), MAXIMUM_APP_COUNT); i++) { 102 final RecentLocationAccesses.Access access = recentLocationAccesses.get(i); 103 final AppEntityInfo appEntityInfo = new AppEntityInfo.Builder() 104 .setIcon(access.icon) 105 .setTitle(access.label) 106 .setSummary(StringUtil.formatRelativeTime(mContext, 107 System.currentTimeMillis() - access.accessFinishTime, false, 108 RelativeDateTimeFormatter.Style.SHORT)) 109 .setOnClickListener((v) -> { 110 final Intent intent = new Intent(Intent.ACTION_MANAGE_APP_PERMISSION); 111 intent.putExtra(Intent.EXTRA_PERMISSION_NAME, 112 Manifest.permission.ACCESS_FINE_LOCATION); 113 intent.putExtra(Intent.EXTRA_PACKAGE_NAME, access.packageName); 114 intent.putExtra(Intent.EXTRA_USER, access.userHandle); 115 mContext.startActivity(intent); 116 }) 117 .build(); 118 mController.setAppEntity(i, appEntityInfo); 119 } 120 for (; i < MAXIMUM_APP_COUNT; i++) { 121 mController.removeAppEntity(i); 122 } 123 } 124 mController.apply(); 125 } 126 } 127