Add "See All" page for Recent Location Access

Screenshots: http://shortn/_UPy8KFSeSj

Bug: 180533061
Test: manual on device
Change-Id: Ib77bc0705835520ed1a2d3b7f662088ed838e53e
This commit is contained in:
Yu-Han Yang
2021-03-04 10:53:39 -08:00
parent d0267d5f8d
commit cdb3551be1
12 changed files with 326 additions and 13 deletions

View File

@@ -3985,7 +3985,7 @@
<string name="managed_profile_location_switch_title">Location for work profile</string>
<!-- [CHAR LIMIT=30] Location settings screen. It's a link that directs the user to a page that
shows the location permission setting for each installed app -->
<string name="location_app_level_permissions">App access to location</string>
<string name="location_app_level_permissions">Manage location permissions</string>
<!-- Summary for app permission on Location settings page when location is off [CHAR LIMIT=NONE] -->
<string name="location_app_permission_summary_location_off">Location is off</string>
<!--
@@ -4010,7 +4010,9 @@
apps have access to location</item>
</plurals>
<!-- [CHAR LIMIT=50] Location settings screen, sub category for recent location access -->
<string name="location_category_recent_location_access">Recent location access</string>
<string name="location_category_recent_location_access">Past 24 hour access</string>
<!-- Location settings screen, displayed when there're more than three recent location access apps [CHAR LIMIT=30] -->
<string name="location_recent_location_access_see_all">See all</string>
<!-- [CHAR LIMIT=30] Location settings screen, button to bring the user to view the details of recent location access -->
<string name="location_recent_location_access_view_details">View details</string>
<!-- Location settings screen, displayed when there's no recent app accessing location

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2021 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:title="@string/location_category_recent_location_access"
android:key="all_recent_location_access"
settings:controller="com.android.settings.location.RecentLocationAccessSeeAllPreferenceController">
</PreferenceScreen>

View File

@@ -27,6 +27,13 @@
settings:controller=
"com.android.settings.location.RecentLocationAccessPreferenceController"/>
<Preference
android:key="recent_location_access_see_all_button"
android:title="@string/location_recent_location_access_see_all"
android:icon="@drawable/ic_chevron_right_24dp"
android:fragment="com.android.settings.location.RecentLocationAccessSeeAllFragment"
settings:searchable="false"/>
<PreferenceCategory
android:key="location_advanced_settings"
android:layout="@layout/preference_category_no_label"

View File

@@ -23,11 +23,18 @@
settings:keywords="@string/keywords_location">
<PreferenceCategory
android:key="recent_location_requests"
android:title="@string/location_category_recent_location_requests"
android:key="recent_location_access"
android:title="@string/location_category_recent_location_access"
settings:controller=
"com.android.settings.location.RecentLocationAccessPreferenceController"/>
<Preference
android:key="recent_location_access_see_all_button"
android:title="@string/location_recent_location_access_see_all"
android:icon="@drawable/ic_chevron_right_24dp"
android:fragment="com.android.settings.location.RecentLocationAccessSeeAllFragment"
settings:searchable="false"/>
<!-- This preference category gets removed if new_recent_location_ui is disabled -->
<Preference
android:key="app_level_permissions"

View File

@@ -23,11 +23,20 @@
settings:keywords="@string/keywords_location">
<PreferenceCategory
android:key="recent_location_requests"
android:title="@string/location_category_recent_location_requests"
android:key="recent_location_access"
android:title="@string/location_category_recent_location_access"
settings:controller=
"com.android.settings.location.RecentLocationAccessPreferenceController"/>
<Preference
android:key="recent_location_access_see_all_button"
android:title="@string/location_recent_location_access_see_all"
android:icon="@drawable/ic_chevron_right_24dp"
android:fragment="com.android.settings.location.RecentLocationAccessSeeAllFragment"
settings:controller="com.android.settings.core.WorkPreferenceController"
settings:forWork="true"
settings:searchable="false"/>
<com.android.settingslib.RestrictedSwitchPreference
android:key="managed_profile_location_switch"
android:title="@string/managed_profile_location_switch_title"

View File

@@ -21,7 +21,7 @@ import android.util.ArrayMap;
import com.android.settings.accounts.AccountDashboardFragment;
import com.android.settings.applications.manageapplications.ManageApplications;
import com.android.settings.location.LocationSettings;
import com.android.settings.location.RecentLocationRequestSeeAllFragment;
import com.android.settings.location.RecentLocationAccessSeeAllFragment;
import java.util.Map;
@@ -44,7 +44,7 @@ public class ProfileFragmentBridge {
ProfileSelectManageApplications.class.getName());
FRAGMENT_MAP.put(LocationSettings.class.getName(),
ProfileSelectLocationFragment.class.getName());
FRAGMENT_MAP.put(RecentLocationRequestSeeAllFragment.class.getName(),
ProfileSelectRecentLocationRequestFragment.class.getName());
FRAGMENT_MAP.put(RecentLocationAccessSeeAllFragment.class.getName(),
ProfileSelectRecentLocationAccessFragment.class.getName());
}
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.dashboard.profileselector;
import android.os.Bundle;
import androidx.fragment.app.Fragment;
import com.android.settings.location.RecentLocationAccessSeeAllFragment;
/**
* Recent location request page for personal/managed profile.
*/
public class ProfileSelectRecentLocationAccessFragment extends ProfileSelectFragment {
@Override
public Fragment[] getFragments() {
final Bundle workOnly = new Bundle();
workOnly.putInt(EXTRA_PROFILE, ProfileType.WORK);
final Fragment workFragment = new RecentLocationAccessSeeAllFragment();
workFragment.setArguments(workOnly);
final Bundle personalOnly = new Bundle();
personalOnly.putInt(EXTRA_PROFILE, ProfileType.PERSONAL);
final Fragment personalFragment = new RecentLocationAccessSeeAllFragment();
personalFragment.setArguments(personalOnly);
return new Fragment[]{
personalFragment, //0
workFragment
};
}
}

View File

@@ -38,6 +38,7 @@ import java.util.List;
* Preference controller that handles the display of apps that access locations.
*/
public class RecentLocationAccessPreferenceController extends LocationBasePreferenceController {
public static final int MAX_APPS = 3;
@VisibleForTesting
RecentLocationAccesses mRecentLocationApps;
private PreferenceCategory mCategoryRecentLocationRequests;
@@ -89,6 +90,9 @@ public class RecentLocationAccessPreferenceController extends LocationBasePrefer
/* showSystemApps= */ false)) {
if (isRequestMatchesProfileType(userManager, access, mType)) {
recentLocationAccesses.add(access);
if (recentLocationAccesses.size() == MAX_APPS) {
break;
}
}
}

View File

@@ -0,0 +1,108 @@
/*
* Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.location;
import android.content.Context;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.dashboard.profileselector.ProfileSelectFragment;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settingslib.search.SearchIndexable;
/** Dashboard Fragment to display all recent location access (apps), sorted by recency. */
@SearchIndexable
public class RecentLocationAccessSeeAllFragment extends DashboardFragment {
private static final String TAG = "RecentLocAccessSeeAll";
public static final String PATH =
"com.android.settings.location.RecentLocationAccessSeeAllFragment";
private static final int MENU_SHOW_SYSTEM = Menu.FIRST + 1;
private static final int MENU_HIDE_SYSTEM = Menu.FIRST + 2;
private boolean mShowSystem = false;
private MenuItem mShowSystemMenu;
private MenuItem mHideSystemMenu;
private RecentLocationAccessSeeAllPreferenceController mController;
@Override
public int getMetricsCategory() {
return MetricsEvent.RECENT_LOCATION_REQUESTS_ALL;
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
final int profileType = getArguments().getInt(ProfileSelectFragment.EXTRA_PROFILE);
mController = use(RecentLocationAccessSeeAllPreferenceController.class);
mController.init(this);
if (profileType != 0) {
mController.setProfileType(profileType);
}
}
@Override
protected int getPreferenceScreenResId() {
return R.xml.location_recent_access_see_all;
}
@Override
protected String getLogTag() {
return TAG;
}
@Override
public boolean onOptionsItemSelected(MenuItem menuItem) {
switch (menuItem.getItemId()) {
case MENU_SHOW_SYSTEM:
case MENU_HIDE_SYSTEM:
mShowSystem = menuItem.getItemId() == MENU_SHOW_SYSTEM;
updateMenu();
if (mController != null) {
mController.setShowSystem(mShowSystem);
}
return true;
default:
return super.onOptionsItemSelected(menuItem);
}
}
private void updateMenu() {
mShowSystemMenu.setVisible(!mShowSystem);
mHideSystemMenu.setVisible(mShowSystem);
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
mShowSystemMenu = menu.add(Menu.NONE, MENU_SHOW_SYSTEM, Menu.NONE,
R.string.menu_show_system);
mHideSystemMenu = menu.add(Menu.NONE, MENU_HIDE_SYSTEM, Menu.NONE,
R.string.menu_hide_system);
updateMenu();
}
/**
* For Search.
*/
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider(R.xml.location_recent_access_see_all);
}

View File

@@ -0,0 +1,110 @@
/*
* Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.location;
import static com.android.settings.location.RecentLocationAccessPreferenceController.createAppPreference;
import static com.android.settings.location.RecentLocationAccessPreferenceController.isRequestMatchesProfileType;
import android.content.Context;
import android.os.UserManager;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.dashboard.profileselector.ProfileSelectFragment;
import com.android.settingslib.location.RecentLocationAccesses;
import com.android.settingslib.widget.AppPreference;
import java.util.ArrayList;
import java.util.List;
/** Preference controller for preference category displaying all recent location access (apps). */
public class RecentLocationAccessSeeAllPreferenceController
extends LocationBasePreferenceController {
private PreferenceScreen mCategoryAllRecentLocationAccess;
private RecentLocationAccesses mRecentLocationAccesses;
private boolean mShowSystem = false;
private Preference mPreference;
private int mType = ProfileSelectFragment.ProfileType.ALL;
public RecentLocationAccessSeeAllPreferenceController(Context context, String key) {
super(context, key);
mRecentLocationAccesses = new RecentLocationAccesses(context);
}
@Override
public void onLocationModeChanged(int mode, boolean restricted) {
mCategoryAllRecentLocationAccess.setEnabled(mLocationEnabler.isEnabled(mode));
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
mCategoryAllRecentLocationAccess = screen.findPreference(getPreferenceKey());
}
@Override
public void updateState(Preference preference) {
mCategoryAllRecentLocationAccess.removeAll();
mPreference = preference;
final UserManager userManager = UserManager.get(mContext);
final List<RecentLocationAccesses.Access> recentLocationAccesses = new ArrayList<>();
for (RecentLocationAccesses.Access access : mRecentLocationAccesses.getAppListSorted(
mShowSystem)) {
if (isRequestMatchesProfileType(userManager, access, mType)) {
recentLocationAccesses.add(access);
}
}
if (recentLocationAccesses.isEmpty()) {
// If there's no item to display, add a "No recent apps" item.
final Preference banner = new AppPreference(mContext);
banner.setTitle(R.string.location_no_recent_apps);
banner.setSelectable(false);
mCategoryAllRecentLocationAccess.addPreference(banner);
} else {
for (RecentLocationAccesses.Access request : recentLocationAccesses) {
final Preference appPreference = createAppPreference(
preference.getContext(),
request, mFragment);
mCategoryAllRecentLocationAccess.addPreference(appPreference);
}
}
}
/**
* Initialize {@link ProfileSelectFragment.ProfileType} of the controller
*
* @param type {@link ProfileSelectFragment.ProfileType} of the controller.
*/
public void setProfileType(@ProfileSelectFragment.ProfileType int type) {
mType = type;
}
/**
* Set the value of {@link #mShowSystem}.
*/
public void setShowSystem(boolean showSystem) {
mShowSystem = showSystem;
if (mPreference != null) {
updateState(mPreference);
}
}
}

View File

@@ -27,7 +27,7 @@ import com.android.settings.fuelgauge.PowerUsageSummary;
import com.android.settings.gestures.GestureNavigationSettingsFragment;
import com.android.settings.gestures.SystemNavigationGestureSettings;
import com.android.settings.location.LocationSettings;
import com.android.settings.location.RecentLocationRequestSeeAllFragment;
import com.android.settings.location.RecentLocationAccessSeeAllFragment;
import com.android.settings.network.NetworkDashboardFragment;
import com.android.settings.notification.zen.ZenModeBlockedEffectsSettings;
import com.android.settings.notification.zen.ZenModeRestrictNotificationsSettings;
@@ -57,7 +57,7 @@ public class CustomSiteMapRegistry {
CUSTOM_SITE_MAP.put(
WifiSettings.class.getName(), NetworkDashboardFragment.class.getName());
CUSTOM_SITE_MAP.put(PowerUsageAdvanced.class.getName(), PowerUsageSummary.class.getName());
CUSTOM_SITE_MAP.put(RecentLocationRequestSeeAllFragment.class.getName(),
CUSTOM_SITE_MAP.put(RecentLocationAccessSeeAllFragment.class.getName(),
LocationSettings.class.getName());
CUSTOM_SITE_MAP.put(UsbDetailsFragment.class.getName(),
ConnectedDeviceDashboardFragment.class.getName());

View File

@@ -29,7 +29,7 @@ import com.android.settings.fuelgauge.PowerUsageSummary;
import com.android.settings.gestures.GestureNavigationSettingsFragment;
import com.android.settings.gestures.SystemNavigationGestureSettings;
import com.android.settings.location.LocationSettings;
import com.android.settings.location.RecentLocationRequestSeeAllFragment;
import com.android.settings.location.RecentLocationAccessSeeAllFragment;
import com.android.settings.network.NetworkDashboardFragment;
import com.android.settings.notification.zen.ZenModeBlockedEffectsSettings;
import com.android.settings.notification.zen.ZenModeRestrictNotificationsSettings;
@@ -73,7 +73,7 @@ public class CustomSiteMapRegistryTest {
@Test
public void shouldContainRecentLocationRequestSeeAllFragmentPairs() {
assertThat(CustomSiteMapRegistry.CUSTOM_SITE_MAP.get(
RecentLocationRequestSeeAllFragment.class.getName())).isEqualTo(
RecentLocationAccessSeeAllFragment.class.getName())).isEqualTo(
LocationSettings.class.getName());
}