diff --git a/res/values/styles.xml b/res/values/styles.xml index 4cbf2c3ba71..4052813c0d8 100644 --- a/res/values/styles.xml +++ b/res/values/styles.xml @@ -572,7 +572,7 @@ middle - diff --git a/res/xml/language_and_input.xml b/res/xml/language_and_input.xml index 5880076bdec..03c83d47285 100644 --- a/res/xml/language_and_input.xml +++ b/res/xml/language_and_input.xml @@ -109,7 +109,7 @@ android:title="@string/spellcheckers_settings_for_work_title" android:fragment="com.android.settings.inputmethod.SpellCheckersSettings" settings:forWork="true" - settings:controller="com.android.settings.language.UserDictionaryForWorkPreferenceController" /> + settings:controller="com.android.settings.core.WorkPreferenceController" /> - - - - \ No newline at end of file diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java index bef4f1bc90f..4144914dbf9 100644 --- a/src/com/android/settings/Utils.java +++ b/src/com/android/settings/Utils.java @@ -191,19 +191,6 @@ public final class Utils extends com.android.settingslib.Utils { return false; } - /** - * Returns the UserManager for a given context - * - * @throws IllegalStateException if no UserManager could be retrieved. - */ - public static UserManager getUserManager(Context context) { - final UserManager um = UserManager.get(context); - if (um == null) { - throw new IllegalStateException("Unable to load UserManager"); - } - return um; - } - /** * Returns true if Monkey is running. */ @@ -679,7 +666,7 @@ public final class Utils extends com.android.settingslib.Utils { * @throws SecurityException if the given userId does not belong to the current user group. */ public static int enforceSameOwner(Context context, int userId) { - final UserManager um = getUserManager(context); + final UserManager um = UserManager.get(context); final int[] profileIds = um.getProfileIdsWithDisabled(UserHandle.myUserId()); if (ArrayUtils.contains(profileIds, userId)) { return userId; @@ -699,7 +686,7 @@ public final class Utils extends com.android.settingslib.Utils { * Returns the user id of the credential owner of the given user id. */ public static int getCredentialOwnerUserId(Context context, int userId) { - final UserManager um = getUserManager(context); + final UserManager um = UserManager.get(context); return um.getCredentialOwnerProfile(userId); } @@ -836,7 +823,7 @@ public final class Utils extends com.android.settingslib.Utils { } public static boolean isDemoUser(Context context) { - return UserManager.isDeviceInDemoMode(context) && getUserManager(context).isDemoUser(); + return UserManager.isDeviceInDemoMode(context) && UserManager.get(context).isDemoUser(); } public static ComponentName getDeviceOwnerComponent(Context context) { diff --git a/src/com/android/settings/core/BasePreferenceController.java b/src/com/android/settings/core/BasePreferenceController.java index 7215bb79159..1985a998d85 100644 --- a/src/com/android/settings/core/BasePreferenceController.java +++ b/src/com/android/settings/core/BasePreferenceController.java @@ -13,6 +13,8 @@ */ package com.android.settings.core; +import static android.content.Intent.EXTRA_USER_ID; + import static com.android.settings.dashboard.DashboardFragment.CATEGORY; import android.annotation.IntDef; @@ -20,6 +22,7 @@ import android.app.settings.SettingsEnums; import android.content.ContentResolver; import android.content.Context; import android.net.Uri; +import android.os.Bundle; import android.os.UserHandle; import android.os.UserManager; import android.provider.SettingsSlicesContract; @@ -204,7 +207,7 @@ public abstract class BasePreferenceController extends AbstractPreferenceControl * The status is used for the convenience methods: {@link #isAvailable()}, * {@link #isSupported()} *

- * The inherited class doesn't need to check work profile is existed or not if + * The inherited class doesn't need to check work profile if * android:forWork="true" is set in preference xml. */ @AvailabilityStatus @@ -337,6 +340,8 @@ public abstract class BasePreferenceController extends AbstractPreferenceControl if (!mIsForWork || mWorkProfileUser == null) { return super.handlePreferenceTreeClick(preference); } + final Bundle extra = preference.getExtras(); + extra.putInt(EXTRA_USER_ID, mWorkProfileUser.getIdentifier()); new SubSettingLauncher(preference.getContext()) .setDestination(preference.getFragment()) .setSourceMetricsCategory(preference.getExtras().getInt(CATEGORY, diff --git a/src/com/android/settings/language/UserDictionaryForWorkPreferenceController.java b/src/com/android/settings/core/WorkPreferenceController.java similarity index 59% rename from src/com/android/settings/language/UserDictionaryForWorkPreferenceController.java rename to src/com/android/settings/core/WorkPreferenceController.java index 99d1c2f35fe..5fdc476d41a 100644 --- a/src/com/android/settings/language/UserDictionaryForWorkPreferenceController.java +++ b/src/com/android/settings/core/WorkPreferenceController.java @@ -14,27 +14,27 @@ * limitations under the License. */ -package com.android.settings.language; +package com.android.settings.core; import android.content.Context; -import com.android.settings.core.BasePreferenceController; +import androidx.annotation.CallSuper; /** - * Preference controller for "UserDictionary for work". - * - * @see UserDictionaryPreferenceController + * Base class to be used directly in Xml with settings:forWork="true" attribute. + * It is used specifically for work profile only preference */ -public final class UserDictionaryForWorkPreferenceController - extends BasePreferenceController { +public class WorkPreferenceController extends BasePreferenceController { - public UserDictionaryForWorkPreferenceController(Context context, String preferenceKey) { + public WorkPreferenceController(Context context, String preferenceKey) { super(context, preferenceKey); } - @AvailabilityStatus - @Override + /** + * Only available when work profile user is existed + */ + @CallSuper public int getAvailabilityStatus() { - return AVAILABLE; + return getWorkProfileUser() != null ? AVAILABLE : DISABLED_FOR_USER; } } diff --git a/src/com/android/settings/dashboard/profileselector/ProfileFragmentBridge.java b/src/com/android/settings/dashboard/profileselector/ProfileFragmentBridge.java index 816decaac5a..04fccb3ddab 100644 --- a/src/com/android/settings/dashboard/profileselector/ProfileFragmentBridge.java +++ b/src/com/android/settings/dashboard/profileselector/ProfileFragmentBridge.java @@ -20,8 +20,8 @@ import android.util.ArrayMap; import com.android.settings.accounts.AccountDashboardFragment; import com.android.settings.applications.manageapplications.ManageApplications; -import com.android.settings.deviceinfo.StorageDashboardFragment; import com.android.settings.location.LocationSettings; +import com.android.settings.location.RecentLocationRequestSeeAllFragment; import java.util.Map; @@ -42,9 +42,9 @@ public class ProfileFragmentBridge { ProfileSelectAccountFragment.class.getName()); FRAGMENT_MAP.put(ManageApplications.class.getName(), ProfileSelectManageApplications.class.getName()); - FRAGMENT_MAP.put(StorageDashboardFragment.class.getName(), - ProfileSelectStorageFragment.class.getName()); FRAGMENT_MAP.put(LocationSettings.class.getName(), ProfileSelectLocationFragment.class.getName()); + FRAGMENT_MAP.put(RecentLocationRequestSeeAllFragment.class.getName(), + ProfileSelectRecentLocationRequestFragment.class.getName()); } } diff --git a/src/com/android/settings/dashboard/profileselector/ProfileSelectFragment.java b/src/com/android/settings/dashboard/profileselector/ProfileSelectFragment.java index 79228c200eb..9ae8284adf2 100644 --- a/src/com/android/settings/dashboard/profileselector/ProfileSelectFragment.java +++ b/src/com/android/settings/dashboard/profileselector/ProfileSelectFragment.java @@ -16,10 +16,13 @@ package com.android.settings.dashboard.profileselector; +import static android.content.Intent.EXTRA_USER_ID; + import android.annotation.IntDef; import android.app.Activity; import android.content.Context; import android.os.Bundle; +import android.os.UserHandle; import android.os.UserManager; import android.view.LayoutInflater; import android.view.View; @@ -27,6 +30,7 @@ import android.view.ViewGroup; import android.widget.FrameLayout; import android.widget.LinearLayout; +import androidx.annotation.VisibleForTesting; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentStatePagerAdapter; import androidx.recyclerview.widget.RecyclerView; @@ -97,21 +101,7 @@ public abstract class ProfileSelectFragment extends DashboardFragment { Bundle savedInstanceState) { mContentView = (ViewGroup) super.onCreateView(inflater, container, savedInstanceState); final Activity activity = getActivity(); - final int intentUser = activity.getIntent().getContentUserHint(); - int selectedTab = 0; - - // Start intent from a specific user eg: adb shell --user 10 - if (intentUser > 0 && Utils.getManagedProfile(UserManager.get(activity)).getIdentifier() - == intentUser) { - selectedTab = WORK_TAB; - } - - // Set selected tab using fragment argument - final int extraTab = getArguments() != null ? getArguments().getInt( - SettingsActivity.EXTRA_SHOW_FRAGMENT_TAB, -1) : -1; - if (extraTab != -1) { - selectedTab = extraTab; - } + final int selectedTab = getTabId(activity, getArguments()); final View tabContainer = mContentView.findViewById(R.id.tab_container); final ViewPager viewPager = tabContainer.findViewById(R.id.view_pager); @@ -155,6 +145,28 @@ public abstract class ProfileSelectFragment extends DashboardFragment { return TAG; } + @VisibleForTesting + int getTabId(Activity activity, Bundle bundle) { + if (bundle != null) { + final int extraTab = bundle.getInt(SettingsActivity.EXTRA_SHOW_FRAGMENT_TAB, -1); + if (extraTab != -1) { + return WORK_TAB; + } + final int userId = bundle.getInt(EXTRA_USER_ID, UserHandle.SYSTEM.getIdentifier()); + final boolean isWorkProfile = UserManager.get(activity).isManagedProfile(userId); + if (isWorkProfile) { + return WORK_TAB; + } + } + // Start intent from a specific user eg: adb shell --user 10 + final int intentUser = activity.getIntent().getContentUserHint(); + if (UserManager.get(activity).isManagedProfile(intentUser)) { + return WORK_TAB; + } + + return PERSONAL_TAB; + } + static class ViewPagerAdapter extends FragmentStatePagerAdapter { private final Fragment[] mChildFragments; diff --git a/src/com/android/settings/dashboard/profileselector/ProfileSelectLocationFragment.java b/src/com/android/settings/dashboard/profileselector/ProfileSelectLocationFragment.java index b256157d502..0d7c4d040e2 100644 --- a/src/com/android/settings/dashboard/profileselector/ProfileSelectLocationFragment.java +++ b/src/com/android/settings/dashboard/profileselector/ProfileSelectLocationFragment.java @@ -46,9 +46,19 @@ public class ProfileSelectLocationFragment extends ProfileSelectFragment { @Override public Fragment[] getFragments() { + + final Bundle workOnly = new Bundle(); + workOnly.putInt(EXTRA_PROFILE, ProfileSelectFragment.ProfileType.WORK); + final Fragment workFragment = new LocationWorkProfileSettings(); + workFragment.setArguments(workOnly); + + final Bundle personalOnly = new Bundle(); + personalOnly.putInt(EXTRA_PROFILE, ProfileSelectFragment.ProfileType.PERSONAL); + final Fragment personalFragment = new LocationPersonalSettings(); + personalFragment.setArguments(personalOnly); return new Fragment[]{ - new LocationPersonalSettings(), - new LocationWorkProfileSettings() + personalFragment, + workFragment }; } } diff --git a/src/com/android/settings/dashboard/profileselector/ProfileSelectRecentLocationRequestFragment.java b/src/com/android/settings/dashboard/profileselector/ProfileSelectRecentLocationRequestFragment.java new file mode 100644 index 00000000000..058ffe4dfd2 --- /dev/null +++ b/src/com/android/settings/dashboard/profileselector/ProfileSelectRecentLocationRequestFragment.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2019 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.RecentLocationRequestSeeAllFragment; + +/** + * Recent location request page for personal/managed profile. + */ +public class ProfileSelectRecentLocationRequestFragment extends ProfileSelectFragment { + + @Override + public Fragment[] getFragments() { + final Bundle workOnly = new Bundle(); + workOnly.putInt(EXTRA_PROFILE, ProfileSelectFragment.ProfileType.WORK); + final Fragment workFragment = new RecentLocationRequestSeeAllFragment(); + workFragment.setArguments(workOnly); + + final Bundle personalOnly = new Bundle(); + personalOnly.putInt(EXTRA_PROFILE, ProfileSelectFragment.ProfileType.PERSONAL); + final Fragment personalFragment = new RecentLocationRequestSeeAllFragment(); + personalFragment.setArguments(personalOnly); + return new Fragment[]{ + personalFragment, //0 + workFragment + }; + } +} diff --git a/src/com/android/settings/dashboard/profileselector/ProfileSelectStorageFragment.java b/src/com/android/settings/dashboard/profileselector/ProfileSelectStorageFragment.java deleted file mode 100644 index bb39cdb9560..00000000000 --- a/src/com/android/settings/dashboard/profileselector/ProfileSelectStorageFragment.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2019 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 android.os.UserHandle; -import android.os.UserManager; -import android.os.storage.VolumeInfo; - -import androidx.fragment.app.Fragment; - -import com.android.settings.R; -import com.android.settings.Utils; -import com.android.settings.deviceinfo.StorageDashboardFragment; -import com.android.settings.deviceinfo.StorageProfileFragment; - -/** - * Storage Setting page for personal/managed profile. - */ -public class ProfileSelectStorageFragment extends ProfileSelectFragment { - @Override - public Fragment[] getFragments() { - - final Bundle storageBundle = new Bundle(); - storageBundle.putString(VolumeInfo.EXTRA_VOLUME_ID, VolumeInfo.ID_PRIVATE_INTERNAL); - storageBundle.putInt(EXTRA_PROFILE, ProfileSelectFragment.ProfileType.PERSONAL); - - final Fragment storageDashboardFragment = new StorageDashboardFragment(); - storageDashboardFragment.setArguments(storageBundle); - - final UserHandle userHandle = Utils.getManagedProfile(UserManager.get(getActivity())); - if (userHandle != null) { - storageBundle.putInt(StorageProfileFragment.USER_ID_EXTRA, userHandle.getIdentifier()); - } - - final Fragment storageProfileFragment = new StorageProfileFragment(); - storageProfileFragment.setArguments(storageBundle); - - return new Fragment[]{ - storageDashboardFragment, - storageProfileFragment - }; - } - - @Override - protected int getPreferenceScreenResId() { - return R.xml.storage_summary_donut; - } -} - diff --git a/src/com/android/settings/location/LocationPersonalSettings.java b/src/com/android/settings/location/LocationPersonalSettings.java index 503937e250f..92796a4bd66 100644 --- a/src/com/android/settings/location/LocationPersonalSettings.java +++ b/src/com/android/settings/location/LocationPersonalSettings.java @@ -21,6 +21,7 @@ import android.content.Context; import com.android.settings.R; import com.android.settings.dashboard.DashboardFragment; +import com.android.settings.dashboard.profileselector.ProfileSelectFragment; /** * Location Setting page for personal profile. @@ -49,9 +50,14 @@ public class LocationPersonalSettings extends DashboardFragment { super.onAttach(context); use(AppLocationPermissionPreferenceController.class).init(this); - use(RecentLocationRequestPreferenceController.class).init(this); use(LocationServicePreferenceController.class).init(this); use(LocationFooterPreferenceController.class).init(this); + + final int profileType = getArguments().getInt(ProfileSelectFragment.EXTRA_PROFILE); + final RecentLocationRequestPreferenceController controller = use( + RecentLocationRequestPreferenceController.class); + controller.init(this); + controller.setProfileType(profileType); } @Override diff --git a/src/com/android/settings/location/LocationWorkProfileSettings.java b/src/com/android/settings/location/LocationWorkProfileSettings.java index 2c5221185b1..2bf5f980cdc 100644 --- a/src/com/android/settings/location/LocationWorkProfileSettings.java +++ b/src/com/android/settings/location/LocationWorkProfileSettings.java @@ -21,6 +21,7 @@ import android.content.Context; import com.android.settings.R; import com.android.settings.dashboard.DashboardFragment; +import com.android.settings.dashboard.profileselector.ProfileSelectFragment; /** * Location Setting page for managed profile. @@ -49,10 +50,15 @@ public class LocationWorkProfileSettings extends DashboardFragment { super.onAttach(context); use(AppLocationPermissionPreferenceController.class).init(this); - use(RecentLocationRequestPreferenceController.class).init(this); use(LocationServiceForWorkPreferenceController.class).init(this); use(LocationFooterPreferenceController.class).init(this); use(LocationForWorkPreferenceController.class).init(this); + + final int profileType = getArguments().getInt(ProfileSelectFragment.EXTRA_PROFILE); + final RecentLocationRequestPreferenceController controller = use( + RecentLocationRequestPreferenceController.class); + controller.init(this); + controller.setProfileType(profileType); } @Override diff --git a/src/com/android/settings/location/RecentLocationRequestPreferenceController.java b/src/com/android/settings/location/RecentLocationRequestPreferenceController.java index 515df46a3c5..d64782691d8 100644 --- a/src/com/android/settings/location/RecentLocationRequestPreferenceController.java +++ b/src/com/android/settings/location/RecentLocationRequestPreferenceController.java @@ -16,6 +16,7 @@ package com.android.settings.location; import android.content.Context; import android.os.Bundle; import android.os.UserHandle; +import android.os.UserManager; import androidx.annotation.VisibleForTesting; import androidx.preference.Preference; @@ -26,15 +27,20 @@ import com.android.settings.R; import com.android.settings.applications.appinfo.AppInfoDashboardFragment; import com.android.settings.core.SubSettingLauncher; import com.android.settings.dashboard.DashboardFragment; +import com.android.settings.dashboard.profileselector.ProfileSelectFragment; import com.android.settingslib.location.RecentLocationApps; import com.android.settingslib.widget.apppreference.AppPreference; +import java.util.ArrayList; import java.util.List; public class RecentLocationRequestPreferenceController extends LocationBasePreferenceController { - private final RecentLocationApps mRecentLocationApps; + public static final int MAX_APPS = 3; + @VisibleForTesting + RecentLocationApps mRecentLocationApps; private PreferenceCategory mCategoryRecentLocationRequests; + private int mType = ProfileSelectFragment.ProfileType.ALL; /** Used in this class and {@link RecentLocationRequestSeeAllPreferenceController} */ static class PackageEntryClickedListener implements Preference.OnPreferenceClickListener { @@ -75,23 +81,27 @@ public class RecentLocationRequestPreferenceController extends LocationBasePrefe super.displayPreference(screen); mCategoryRecentLocationRequests = screen.findPreference(getPreferenceKey()); final Context prefContext = mCategoryRecentLocationRequests.getContext(); - final List recentLocationRequests = - mRecentLocationApps.getAppListSorted(false); - if (recentLocationRequests.size() > 3) { - // Display the top 3 preferences to container in original order. - for (int i = 0; i < 3; i++) { - mCategoryRecentLocationRequests.addPreference( - createAppPreference(prefContext, recentLocationRequests.get(i))); + final List recentLocationRequests = new ArrayList<>(); + final UserManager userManager = UserManager.get(mContext); + for (RecentLocationApps.Request request : mRecentLocationApps.getAppListSorted( + false /* systemApps */)) { + if (isRequestMatchesProfileType(userManager, request, mType)) { + recentLocationRequests.add(request); + if (recentLocationRequests.size() == MAX_APPS) { + break; + } } - } else if (recentLocationRequests.size() > 0) { + } + + if (recentLocationRequests.size() > 0) { // Add preferences to container in original order (already sorted by recency). for (RecentLocationApps.Request request : recentLocationRequests) { mCategoryRecentLocationRequests.addPreference( - createAppPreference(prefContext, request)); + createAppPreference(prefContext, request, mFragment)); } } else { // If there's no item to display, add a "No recent apps" item. - final Preference banner = createAppPreference(prefContext); + final Preference banner = new AppPreference(prefContext); banner.setTitle(R.string.location_no_recent_apps); banner.setSelectable(false); mCategoryRecentLocationRequests.addPreference(banner); @@ -103,19 +113,42 @@ public class RecentLocationRequestPreferenceController extends LocationBasePrefe mCategoryRecentLocationRequests.setEnabled(mLocationEnabler.isEnabled(mode)); } - @VisibleForTesting - AppPreference createAppPreference(Context prefContext) { - return new AppPreference(prefContext); + /** + * Initialize {@link ProfileSelectFragment.ProfileType} of the controller + * + * @param type {@link ProfileSelectFragment.ProfileType} of the controller. + */ + public void setProfileType(@ProfileSelectFragment.ProfileType int type) { + mType = type; } - @VisibleForTesting - AppPreference createAppPreference(Context prefContext, RecentLocationApps.Request request) { - final AppPreference pref = createAppPreference(prefContext); - pref.setSummary(request.contentDescription); + /** + * Create a {@link AppPreference} + */ + public static AppPreference createAppPreference(Context prefContext, + RecentLocationApps.Request request, DashboardFragment fragment) { + final AppPreference pref = new AppPreference(prefContext); pref.setIcon(request.icon); pref.setTitle(request.label); pref.setOnPreferenceClickListener(new PackageEntryClickedListener( - mFragment, request.packageName, request.userHandle)); + fragment, request.packageName, request.userHandle)); return pref; } + + /** + * Return if the {@link RecentLocationApps.Request} matches current UI + * {@ProfileSelectFragment.ProfileType} + */ + public static boolean isRequestMatchesProfileType(UserManager userManager, + RecentLocationApps.Request request, @ProfileSelectFragment.ProfileType int type) { + final boolean isWorkProfile = userManager.isManagedProfile( + request.userHandle.getIdentifier()); + if (isWorkProfile && (type & ProfileSelectFragment.ProfileType.WORK) != 0) { + return true; + } + if (!isWorkProfile && (type & ProfileSelectFragment.ProfileType.PERSONAL) != 0) { + return true; + } + return false; + } } diff --git a/src/com/android/settings/location/RecentLocationRequestSeeAllFragment.java b/src/com/android/settings/location/RecentLocationRequestSeeAllFragment.java index fc2a5fed00b..48a6aec5ec4 100644 --- a/src/com/android/settings/location/RecentLocationRequestSeeAllFragment.java +++ b/src/com/android/settings/location/RecentLocationRequestSeeAllFragment.java @@ -23,6 +23,7 @@ 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; @@ -49,9 +50,11 @@ public class RecentLocationRequestSeeAllFragment extends DashboardFragment { @Override public void onAttach(Context context) { super.onAttach(context); + final int profileType = getArguments().getInt(ProfileSelectFragment.EXTRA_PROFILE); mController = use(RecentLocationRequestSeeAllPreferenceController.class); mController.init(this); + mController.setProfileType(profileType); } @Override diff --git a/src/com/android/settings/location/RecentLocationRequestSeeAllPreferenceController.java b/src/com/android/settings/location/RecentLocationRequestSeeAllPreferenceController.java index 4ed9d13add2..df0fa40087c 100644 --- a/src/com/android/settings/location/RecentLocationRequestSeeAllPreferenceController.java +++ b/src/com/android/settings/location/RecentLocationRequestSeeAllPreferenceController.java @@ -15,16 +15,21 @@ */ package com.android.settings.location; -import android.content.Context; +import static com.android.settings.location.RecentLocationRequestPreferenceController.createAppPreference; +import static com.android.settings.location.RecentLocationRequestPreferenceController.isRequestMatchesProfileType; + +import android.content.Context; +import android.os.UserManager; -import androidx.annotation.VisibleForTesting; 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.RecentLocationApps; import com.android.settingslib.widget.apppreference.AppPreference; +import java.util.ArrayList; import java.util.List; /** Preference controller for preference category displaying all recent location requests. */ @@ -35,6 +40,7 @@ public class RecentLocationRequestSeeAllPreferenceController private RecentLocationApps mRecentLocationApps; private boolean mShowSystem = false; private Preference mPreference; + private int mType = ProfileSelectFragment.ProfileType.ALL; public RecentLocationRequestSeeAllPreferenceController(Context context, String key) { super(context, key); @@ -56,33 +62,39 @@ public class RecentLocationRequestSeeAllPreferenceController public void updateState(Preference preference) { mCategoryAllRecentLocationRequests.removeAll(); mPreference = preference; - List requests = mRecentLocationApps.getAppListSorted( - mShowSystem); - if (requests.isEmpty()) { + + final UserManager userManager = UserManager.get(mContext); + final List recentLocationRequests = new ArrayList<>(); + for (RecentLocationApps.Request request : mRecentLocationApps.getAppListSorted( + mShowSystem)) { + if (isRequestMatchesProfileType(userManager, request, mType)) { + recentLocationRequests.add(request); + } + } + + if (recentLocationRequests.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); mCategoryAllRecentLocationRequests.addPreference(banner); } else { - for (RecentLocationApps.Request request : requests) { - Preference appPreference = createAppPreference(preference.getContext(), request); + for (RecentLocationApps.Request request : recentLocationRequests) { + final Preference appPreference = createAppPreference( + preference.getContext(), + request, mFragment); mCategoryAllRecentLocationRequests.addPreference(appPreference); } } } - @VisibleForTesting - AppPreference createAppPreference( - Context prefContext, RecentLocationApps.Request request) { - final AppPreference pref = new AppPreference(prefContext); - pref.setSummary(request.contentDescription); - pref.setIcon(request.icon); - pref.setTitle(request.label); - pref.setOnPreferenceClickListener( - new RecentLocationRequestPreferenceController.PackageEntryClickedListener( - mFragment, request.packageName, request.userHandle)); - return pref; + /** + * Initialize {@link ProfileSelectFragment.ProfileType} of the controller + * + * @param type {@link ProfileSelectFragment.ProfileType} of the controller. + */ + public void setProfileType(@ProfileSelectFragment.ProfileType int type) { + mType = type; } public void setShowSystem(boolean showSystem) { diff --git a/tests/robotests/src/com/android/settings/dashboard/profileselector/ProfileSelectFragmentTest.java b/tests/robotests/src/com/android/settings/dashboard/profileselector/ProfileSelectFragmentTest.java index 8580b4ca85d..3f6f95ad69a 100644 --- a/tests/robotests/src/com/android/settings/dashboard/profileselector/ProfileSelectFragmentTest.java +++ b/tests/robotests/src/com/android/settings/dashboard/profileselector/ProfileSelectFragmentTest.java @@ -16,6 +16,8 @@ package com.android.settings.dashboard.profileselector; +import static android.content.Intent.EXTRA_USER_ID; + import static com.android.settings.dashboard.profileselector.ProfileSelectFragment.PERSONAL_TAB; import static com.android.settings.dashboard.profileselector.ProfileSelectFragment.WORK_TAB; @@ -27,22 +29,13 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.content.Intent; import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; -import androidx.preference.PreferenceFragmentCompat; -import androidx.recyclerview.widget.RecyclerView; -import com.android.settings.R; import com.android.settings.SettingsActivity; import com.android.settings.SettingsPreferenceFragmentTest; - -import com.google.android.material.tabs.TabLayout; +import com.android.settings.testutils.shadow.ShadowUserManager; import org.junit.Before; import org.junit.Test; @@ -52,16 +45,18 @@ import org.robolectric.Robolectric; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; -import org.robolectric.annotation.Implementation; -import org.robolectric.annotation.Implements; -import org.robolectric.shadows.androidx.fragment.FragmentController; + +import java.util.HashSet; +import java.util.Set; @RunWith(RobolectricTestRunner.class) +@Config(shadows = {ShadowUserManager.class}) public class ProfileSelectFragmentTest { private Context mContext; private TestProfileSelectFragment mFragment; private FragmentActivity mActivity; + private ShadowUserManager mUserManager; @Before public void setUp() { @@ -71,30 +66,51 @@ public class ProfileSelectFragmentTest { mFragment = spy(new TestProfileSelectFragment()); when(mFragment.getContext()).thenReturn(mContext); when(mFragment.getActivity()).thenReturn(mActivity); + mUserManager = ShadowUserManager.getShadow(); } @Test - @Config(shadows = ShadowPreferenceFragmentCompat.class) - public void onCreateView_no_setCorrectTab() { - FragmentController.of(mFragment, new Intent()).create(0 /* containerViewId*/, - null /* bundle */).start().resume().visible().get(); - final TabLayout tabs = mFragment.getView().findViewById(R.id.tabs); - - assertThat(tabs.getSelectedTabPosition()).isEqualTo(PERSONAL_TAB); + public void getTabId_no_setCorrectTab() { + assertThat(mFragment.getTabId(mActivity, null)).isEqualTo(PERSONAL_TAB); } @Test - @Config(shadows = ShadowPreferenceFragmentCompat.class) - public void onCreateView_setArgument_setCorrectTab() { + public void getTabId_setArgument_setCorrectTab() { final Bundle bundle = new Bundle(); bundle.putInt(SettingsActivity.EXTRA_SHOW_FRAGMENT_TAB, WORK_TAB); - mFragment.setArguments(bundle); - FragmentController.of(mFragment, new Intent()).create(0 /* containerViewId*/, - bundle).start().resume().visible().get(); - final TabLayout tabs = mFragment.getView().findViewById(R.id.tabs); + assertThat(mFragment.getTabId(mActivity, bundle)).isEqualTo(WORK_TAB); + } - assertThat(tabs.getSelectedTabPosition()).isEqualTo(WORK_TAB); + @Test + public void getTabId_setWorkId_getCorrectTab() { + final Bundle bundle = new Bundle(); + bundle.putInt(EXTRA_USER_ID, 10); + final Set profileIds = new HashSet<>(); + profileIds.add(10); + mUserManager.setManagedProfiles(profileIds); + + assertThat(mFragment.getTabId(mActivity, bundle)).isEqualTo(WORK_TAB); + } + + @Test + public void getTabId_setPersonalId_getCorrectTab() { + final Bundle bundle = new Bundle(); + bundle.putInt(EXTRA_USER_ID, 0); + + assertThat(mFragment.getTabId(mActivity, bundle)).isEqualTo(PERSONAL_TAB); + } + + @Test + public void getTabId_setPersonalIdByIntent_getCorrectTab() { + final Set profileIds = new HashSet<>(); + profileIds.add(10); + mUserManager.setManagedProfiles(profileIds); + final Intent intent = spy(new Intent()); + when(intent.getContentUserHint()).thenReturn(10); + when(mActivity.getIntent()).thenReturn(intent); + + assertThat(mFragment.getTabId(mActivity, null)).isEqualTo(WORK_TAB); } public static class TestProfileSelectFragment extends ProfileSelectFragment { @@ -107,41 +123,4 @@ public class ProfileSelectFragmentTest { }; } } - - @Implements(PreferenceFragmentCompat.class) - public static class ShadowPreferenceFragmentCompat { - - private Context mContext; - - @Implementation - protected View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, - @Nullable Bundle savedInstanceState) { - mContext = inflater.getContext(); - return inflater.inflate(R.layout.preference_list_fragment, container); - } - - @Implementation - protected RecyclerView getListView() { - final RecyclerView recyclerView = new RecyclerView(mContext); - recyclerView.setAdapter(new RecyclerView.Adapter() { - @NonNull - @Override - public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, - int i) { - return null; - } - - @Override - public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int i) { - - } - - @Override - public int getItemCount() { - return 0; - } - }); - return recyclerView; - } - } } diff --git a/tests/robotests/src/com/android/settings/dashboard/profileselector/ProfileSelectLocationFragmentTest.java b/tests/robotests/src/com/android/settings/dashboard/profileselector/ProfileSelectLocationFragmentTest.java new file mode 100644 index 00000000000..f463bec5862 --- /dev/null +++ b/tests/robotests/src/com/android/settings/dashboard/profileselector/ProfileSelectLocationFragmentTest.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2019 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 static com.android.settings.dashboard.profileselector.ProfileSelectFragment.EXTRA_PROFILE; + +import static com.google.common.truth.Truth.assertThat; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; + +@RunWith(RobolectricTestRunner.class) +public class ProfileSelectLocationFragmentTest { + + private ProfileSelectLocationFragment mProfileSelectLocationFragment; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mProfileSelectLocationFragment = new ProfileSelectLocationFragment(); + } + + @Test + public void getFragments_containsCorrectBundle() { + assertThat(mProfileSelectLocationFragment.getFragments().length).isEqualTo(2); + assertThat(mProfileSelectLocationFragment.getFragments()[0].getArguments().getInt( + EXTRA_PROFILE, -1)).isEqualTo(ProfileSelectFragment.ProfileType.PERSONAL); + assertThat(mProfileSelectLocationFragment.getFragments()[1].getArguments().getInt( + EXTRA_PROFILE, -1)).isEqualTo(ProfileSelectFragment.ProfileType.WORK); + } +} diff --git a/tests/robotests/src/com/android/settings/location/RecentLocationRequestPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/location/RecentLocationRequestPreferenceControllerTest.java new file mode 100644 index 00000000000..545a3584e6e --- /dev/null +++ b/tests/robotests/src/com/android/settings/location/RecentLocationRequestPreferenceControllerTest.java @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2019 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 org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.os.UserHandle; + +import androidx.preference.PreferenceCategory; +import androidx.preference.PreferenceScreen; + +import com.android.settings.dashboard.profileselector.ProfileSelectFragment; +import com.android.settings.testutils.shadow.ShadowUserManager; +import com.android.settingslib.location.RecentLocationApps; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +@RunWith(RobolectricTestRunner.class) +@Config(shadows = {ShadowUserManager.class}) +public class RecentLocationRequestPreferenceControllerTest { + @Mock + private PreferenceScreen mScreen; + @Mock + private PreferenceCategory mCategory; + private Context mContext; + private RecentLocationRequestPreferenceController mController; + private ShadowUserManager mUserManager; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application; + mController = spy( + new RecentLocationRequestPreferenceController(mContext, "key")); + when(mCategory.getContext()).thenReturn(mContext); + when(mScreen.findPreference("key")).thenReturn(mCategory); + mUserManager = ShadowUserManager.getShadow(); + mController.mRecentLocationApps = spy(new RecentLocationApps(mContext)); + } + + @Test + public void updateState_whenAppListMoreThanThree_shouldDisplayTopThreeApps() { + final List requests = createMockRequest(6); + when(mController.mRecentLocationApps.getAppListSorted(false)).thenReturn(requests); + + mController.displayPreference(mScreen); + + verify(mCategory, times(3)).addPreference(any()); + } + + @Test + public void updateState_workProfile_shouldShowOnlyWorkProfileApps() { + final List requests = createMockRequest(6); + when(mController.mRecentLocationApps.getAppListSorted(false)).thenReturn(requests); + mController.setProfileType(ProfileSelectFragment.ProfileType.WORK); + final Set profileIds = new HashSet<>(); + profileIds.add(4); + profileIds.add(5); + mUserManager.setManagedProfiles(profileIds); + + mController.displayPreference(mScreen); + + // contains userId 4 and userId 5 + verify(mCategory, times(2)).addPreference(any()); + } + + @Test + public void updateState_Personal_shouldShowOnlyPersonalApps() { + final List requests = createMockRequest(6); + when(mController.mRecentLocationApps.getAppListSorted(false)).thenReturn(requests); + mController.setProfileType(ProfileSelectFragment.ProfileType.PERSONAL); + final Set profileIds = new HashSet<>(); + for (int i = 0; i < 4; i++) { + profileIds.add(i); + } + mUserManager.setManagedProfiles(profileIds); + + mController.displayPreference(mScreen); + + // contains userId 4 and userId 5 + verify(mCategory, times(2)).addPreference(any()); + } + + private List createMockRequest(int count) { + final List requests = new ArrayList<>(); + for (int i = 0; i < count; i++) { + final Drawable icon = mock(Drawable.class); + // Add mock accesses + final RecentLocationApps.Request request = new RecentLocationApps.Request( + "packageName", UserHandle.of(i), icon, + "appTitle" + i, false, "appSummary" + i, 1000 - i); + requests.add(request); + } + return requests; + } +} diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowUserManager.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowUserManager.java index a85fe107b3c..659c5de770c 100644 --- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowUserManager.java +++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowUserManager.java @@ -27,8 +27,8 @@ import com.google.android.collect.Maps; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; -import org.robolectric.shadow.api.Shadow; import org.robolectric.annotation.Resetter; +import org.robolectric.shadow.api.Shadow; import java.util.ArrayList; import java.util.Collections; @@ -132,6 +132,16 @@ public class ShadowUserManager extends org.robolectric.shadows.ShadowUserManager return mUserSwitchEnabled; } + @Implementation + protected boolean isManagedProfile(int userId) { + return mManagedProfiles.contains(userId); + } + + public void setManagedProfiles(Set profileIds) { + mManagedProfiles.clear(); + mManagedProfiles.addAll(profileIds); + } + public void setUserSwitcherEnabled(boolean userSwitchEnabled) { mUserSwitchEnabled = userSwitchEnabled; }