diff --git a/res/values/strings.xml b/res/values/strings.xml index 8b0cd67d331..80063b6777e 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -11685,6 +11685,13 @@ Use data from either SIM depending on coverage and availability + + Restart to use 2 SIMs + + To use 2 SIMs at once, restart your device, then turn on both SIMs + + Use %1$s only + Data only @@ -13002,11 +13009,6 @@ Select Grammatical gender - - Quarantined Apps - - Unquarantine app - Scanning for deceptive apps diff --git a/res/xml/development_settings.xml b/res/xml/development_settings.xml index c0b6560b9a4..1fdfcaf2e96 100644 --- a/res/xml/development_settings.xml +++ b/res/xml/development_settings.xml @@ -769,12 +769,6 @@ android:title="@string/enable_notes_role_title" android:summary="@string/enable_notes_role_summary" /> - - - - - - - \ No newline at end of file diff --git a/res/xml/user_aspect_ratio_details.xml b/res/xml/user_aspect_ratio_details.xml index 44a7589fe76..24c32718468 100644 --- a/res/xml/user_aspect_ratio_details.xml +++ b/res/xml/user_aspect_ratio_details.xml @@ -28,7 +28,8 @@ settings:searchable="false"/> + android:key="header_view" + android:order="-999"/> 0) { return AVAILABLE; } return UNSUPPORTED_ON_DEVICE; diff --git a/src/com/android/settings/accounts/AccountPreferenceController.java b/src/com/android/settings/accounts/AccountPreferenceController.java index 2d862d6f093..4f03303c372 100644 --- a/src/com/android/settings/accounts/AccountPreferenceController.java +++ b/src/com/android/settings/accounts/AccountPreferenceController.java @@ -311,11 +311,10 @@ public class AccountPreferenceController extends AbstractPreferenceController // should be shown or not. if (((profile.isManagedProfile() && (mType & ProfileSelectFragment.ProfileType.WORK) != 0) - || (Flags.allowPrivateProfile() - && profile.isPrivateProfile() + || (isPrivateProfile(profile) && (mType & ProfileSelectFragment.ProfileType.PRIVATE) != 0) || (!profile.isManagedProfile() - && !(Flags.allowPrivateProfile() && profile.isPrivateProfile()) + && !isPrivateProfile(profile) && (mType & ProfileSelectFragment.ProfileType.PERSONAL) != 0)) && !(mUm.getUserProperties(profile.getUserHandle()) .getShowInQuietMode() == UserProperties.SHOW_IN_QUIET_MODE_HIDDEN @@ -338,6 +337,12 @@ public class AccountPreferenceController extends AbstractPreferenceController mFragment.forceUpdatePreferences(); } + private static boolean isPrivateProfile(UserInfo profile) { + return Flags.allowPrivateProfile() + && android.multiuser.Flags.enablePrivateSpaceFeatures() + && profile.isPrivateProfile(); + } + private void updateProfileUi(final UserInfo userInfo) { if (mFragment.getPreferenceManager() == null) { return; diff --git a/src/com/android/settings/applications/appcompat/UserAspectRatioDetails.java b/src/com/android/settings/applications/appcompat/UserAspectRatioDetails.java index ef054dfa405..cbc5a7b6100 100644 --- a/src/com/android/settings/applications/appcompat/UserAspectRatioDetails.java +++ b/src/com/android/settings/applications/appcompat/UserAspectRatioDetails.java @@ -66,7 +66,8 @@ public class UserAspectRatioDetails extends AppInfoBase implements private static final String TAG = UserAspectRatioDetails.class.getSimpleName(); private static final String KEY_HEADER_SUMMARY = "app_aspect_ratio_summary"; - private static final String KEY_HEADER_BUTTONS = "header_view"; + @VisibleForTesting + static final String KEY_HEADER_BUTTONS = "header_view"; private static final String KEY_PREF_HALF_SCREEN = "half_screen_pref"; private static final String KEY_PREF_DISPLAY_SIZE = "display_size_pref"; @@ -237,6 +238,7 @@ public class UserAspectRatioDetails extends AppInfoBase implements return; } pref.setTitle(mUserAspectRatioManager.getAccessibleEntry(aspectRatio, mPackageName)); + pref.setOrder(getAspectRatioManager().getUserMinAspectRatioOrder(aspectRatio)); pref.setOnClickListener(this); mKeyToAspectRatioMap.put(key, aspectRatio); mAspectRatioPreferences.add(pref); diff --git a/src/com/android/settings/applications/appcompat/UserAspectRatioManager.java b/src/com/android/settings/applications/appcompat/UserAspectRatioManager.java index 3bf61099f13..0550a9af426 100644 --- a/src/com/android/settings/applications/appcompat/UserAspectRatioManager.java +++ b/src/com/android/settings/applications/appcompat/UserAspectRatioManager.java @@ -44,6 +44,7 @@ import android.os.RemoteException; import android.os.UserHandle; import android.provider.DeviceConfig; import android.util.ArrayMap; +import android.util.SparseIntArray; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -76,6 +77,7 @@ public class UserAspectRatioManager { /** Apps that have launcher entry defined in manifest */ private final Map mUserAspectRatioMap; private final Map mUserAspectRatioA11yMap; + private final SparseIntArray mUserAspectRatioOrder; public UserAspectRatioManager(@NonNull Context context) { this(context, AppGlobals.getPackageManager()); @@ -86,6 +88,7 @@ public class UserAspectRatioManager { mContext = context; mIPm = pm; mUserAspectRatioA11yMap = new ArrayMap<>(); + mUserAspectRatioOrder = new SparseIntArray(); mUserAspectRatioMap = getUserMinAspectRatioMapping(); } @@ -152,6 +155,14 @@ public class UserAspectRatioManager { return getUserMinAspectRatioEntry(aspectRatio, packageName, userId); } + /** + * @return the order of the aspect ratio option corresponding to + * config_userAspectRatioOverrideValues + */ + int getUserMinAspectRatioOrder(@PackageManager.UserMinAspectRatio int option) { + return mUserAspectRatioOrder.get(option); + } + /** * Whether user aspect ratio option is specified in * {@link R.array.config_userAspectRatioOverrideValues} @@ -224,7 +235,6 @@ public class UserAspectRatioManager { && isFullscreenCompatChangeEnabled(pkgName, userId); } - @VisibleForTesting boolean isFullscreenCompatChangeEnabled(String pkgName, int userId) { return CompatChanges.isChangeEnabled( OVERRIDE_ANY_ORIENTATION_TO_USER, pkgName, UserHandle.of(userId)); @@ -281,6 +291,7 @@ public class UserAspectRatioManager { mUserAspectRatioA11yMap.put(aspectRatioVal, accessibleSequence); } userMinAspectRatioMap.put(aspectRatioVal, aspectRatioString); + mUserAspectRatioOrder.put(aspectRatioVal, i); } } if (!userMinAspectRatioMap.containsKey(USER_MIN_ASPECT_RATIO_UNSET)) { @@ -290,6 +301,8 @@ public class UserAspectRatioManager { if (mIsUserMinAspectRatioAppDefaultFlagEnabled) { userMinAspectRatioMap.put(USER_MIN_ASPECT_RATIO_APP_DEFAULT, userMinAspectRatioMap.get(USER_MIN_ASPECT_RATIO_UNSET)); + mUserAspectRatioOrder.put(USER_MIN_ASPECT_RATIO_APP_DEFAULT, + mUserAspectRatioOrder.get(USER_MIN_ASPECT_RATIO_UNSET)); if (mUserAspectRatioA11yMap.containsKey(USER_MIN_ASPECT_RATIO_UNSET)) { mUserAspectRatioA11yMap.put(USER_MIN_ASPECT_RATIO_APP_DEFAULT, mUserAspectRatioA11yMap.get(USER_MIN_ASPECT_RATIO_UNSET)); diff --git a/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminListPreferenceController.java b/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminListPreferenceController.java index 640f21dec0e..86c11c21e09 100644 --- a/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminListPreferenceController.java +++ b/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminListPreferenceController.java @@ -167,8 +167,9 @@ public class DeviceAdminListPreferenceController extends BasePreferenceControlle } private boolean shouldSkipProfile(UserHandle profile) { - return android.os.Flags.allowPrivateProfile() + return android.os.Flags.allowPrivateProfile() && android.multiuser.Flags.handleInterleavedSettingsForPrivateSpace() + && android.multiuser.Flags.enablePrivateSpaceFeatures() && mUm.isQuietModeEnabled(profile) && mUm.getUserProperties(profile).getShowInQuietMode() == UserProperties.SHOW_IN_QUIET_MODE_HIDDEN; diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroduction.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroduction.java index f92cfbf6696..26965fae758 100644 --- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroduction.java +++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroduction.java @@ -340,6 +340,9 @@ public class FingerprintEnrollIntroduction extends BiometricEnrollIntroduction { final List props = mFingerprintManager.getSensorPropertiesInternal(); // This will need to be updated for devices with multiple fingerprint sensors + if (props == null || props.isEmpty()) { + return R.string.fingerprint_intro_error_unknown; + } final int max = props.get(0).maxEnrollmentsPerUser; final int numEnrolledFingerprints = mFingerprintManager.getEnrolledFingerprints(mUserId).size(); diff --git a/src/com/android/settings/dashboard/profileselector/ProfileSelectFragment.java b/src/com/android/settings/dashboard/profileselector/ProfileSelectFragment.java index 53a55542848..e8f407bd170 100644 --- a/src/com/android/settings/dashboard/profileselector/ProfileSelectFragment.java +++ b/src/com/android/settings/dashboard/profileselector/ProfileSelectFragment.java @@ -239,7 +239,9 @@ public abstract class ProfileSelectFragment extends DashboardFragment { return WORK_TAB; } UserInfo userInfo = UserManager.get(activity).getUserInfo(userId); - if (Flags.allowPrivateProfile() && userInfo != null && userInfo.isPrivateProfile()) { + if (Flags.allowPrivateProfile() + && android.multiuser.Flags.enablePrivateSpaceFeatures() + && userInfo != null && userInfo.isPrivateProfile()) { return PRIVATE_TAB; } } @@ -249,7 +251,9 @@ public abstract class ProfileSelectFragment extends DashboardFragment { return WORK_TAB; } UserInfo userInfo = UserManager.get(activity).getUserInfo(intentUser); - if (Flags.allowPrivateProfile() && userInfo != null && userInfo.isPrivateProfile()) { + if (Flags.allowPrivateProfile() + && android.multiuser.Flags.enablePrivateSpaceFeatures() + && userInfo != null && userInfo.isPrivateProfile()) { return PRIVATE_TAB; } @@ -260,7 +264,7 @@ public abstract class ProfileSelectFragment extends DashboardFragment { final DevicePolicyManager devicePolicyManager = getContext().getSystemService(DevicePolicyManager.class); - if (Flags.allowPrivateProfile()) { + if (Flags.allowPrivateProfile() && android.multiuser.Flags.enablePrivateSpaceFeatures()) { int tabForPosition = ((ViewPagerAdapter) mViewPager.getAdapter()).getTabForPosition(position); @@ -331,7 +335,9 @@ public abstract class ProfileSelectFragment extends DashboardFragment { ProfileType.WORK, bundle != null ? bundle.deepCopy() : new Bundle(), workFragmentConstructor)); - } else if (Flags.allowPrivateProfile() && userInfo.isPrivateProfile()) { + } else if (Flags.allowPrivateProfile() + && android.multiuser.Flags.enablePrivateSpaceFeatures() + && userInfo.isPrivateProfile()) { if (!privateSpaceInfoProvider.isPrivateSpaceLocked(context)) { fragments.add(createAndGetFragment( ProfileType.PRIVATE, diff --git a/src/com/android/settings/dashboard/profileselector/UserAdapter.java b/src/com/android/settings/dashboard/profileselector/UserAdapter.java index c9e49f17558..40d1a93e5d7 100644 --- a/src/com/android/settings/dashboard/profileselector/UserAdapter.java +++ b/src/com/android/settings/dashboard/profileselector/UserAdapter.java @@ -87,6 +87,7 @@ public class UserAdapter extends BaseAdapter { return resources.getString(WORK_CATEGORY_HEADER, () -> context.getString(com.android.settingslib.R.string.category_work)); } else if (android.os.Flags.allowPrivateProfile() + && android.multiuser.Flags.enablePrivateSpaceFeatures() && mUserManager.getUserInfo(userId).isPrivateProfile()) { return resources.getString(PRIVATE_CATEGORY_HEADER, () -> context.getString(com.android.settingslib.R.string.category_private)); diff --git a/src/com/android/settings/development/quarantine/OWNERS b/src/com/android/settings/development/quarantine/OWNERS deleted file mode 100644 index d4de31a9042..00000000000 --- a/src/com/android/settings/development/quarantine/OWNERS +++ /dev/null @@ -1,4 +0,0 @@ -# Bug component: 316234 - -sudheersai@google.com -yamasani@google.com \ No newline at end of file diff --git a/src/com/android/settings/development/quarantine/QuarantinedAppPreference.java b/src/com/android/settings/development/quarantine/QuarantinedAppPreference.java deleted file mode 100644 index 6ad1f86fbcf..00000000000 --- a/src/com/android/settings/development/quarantine/QuarantinedAppPreference.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2023 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.development.quarantine; - -import android.content.Context; -import android.graphics.drawable.Drawable; - -import androidx.preference.PreferenceViewHolder; - -import com.android.settings.R; -import com.android.settingslib.applications.AppUtils; -import com.android.settingslib.applications.ApplicationsState.AppEntry; -import com.android.settingslib.utils.ThreadUtils; -import com.android.settingslib.widget.AppSwitchPreference; - -public class QuarantinedAppPreference extends AppSwitchPreference { - private final AppEntry mEntry; - private Drawable mCacheIcon; - - public QuarantinedAppPreference(Context context, AppEntry entry) { - super(context); - mEntry = entry; - mCacheIcon = AppUtils.getIconFromCache(mEntry); - - mEntry.ensureLabel(context); - setKey(generateKey(mEntry)); - if (mCacheIcon != null) { - setIcon(mCacheIcon); - } else { - setIcon(R.drawable.empty_icon); - } - updateState(); - } - - static String generateKey(AppEntry entry) { - return entry.info.packageName + "|" + entry.info.uid; - } - - public AppEntry getEntry() { - return mEntry; - } - - @Override - public void onBindViewHolder(PreferenceViewHolder holder) { - if (mCacheIcon == null) { - ThreadUtils.postOnBackgroundThread(() -> { - final Drawable icon = AppUtils.getIcon(getContext(), mEntry); - ThreadUtils.postOnMainThread(() -> { - setIcon(icon); - mCacheIcon = icon; - }); - }); - } - super.onBindViewHolder(holder); - } - - void updateState() { - setTitle(mEntry.label); - setChecked((boolean) mEntry.extraInfo); - notifyChanged(); - } -} diff --git a/src/com/android/settings/development/quarantine/QuarantinedAppStateBridge.java b/src/com/android/settings/development/quarantine/QuarantinedAppStateBridge.java deleted file mode 100644 index 206b922a23f..00000000000 --- a/src/com/android/settings/development/quarantine/QuarantinedAppStateBridge.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2023 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.development.quarantine; - -import android.content.Context; -import android.content.pm.PackageManager; -import android.os.UserHandle; - -import com.android.settings.applications.AppStateBaseBridge; -import com.android.settingslib.applications.ApplicationsState; -import com.android.settingslib.applications.ApplicationsState.AppEntry; - -import java.util.ArrayList; - -public class QuarantinedAppStateBridge extends AppStateBaseBridge { - private Context mContext; - - public QuarantinedAppStateBridge(Context context, - ApplicationsState appState, Callback callback) { - super(appState, callback); - mContext = context; - } - - @Override - protected void loadAllExtraInfo() { - final ArrayList apps = mAppSession.getAllApps(); - for (int i = 0; i < apps.size(); i++) { - final AppEntry app = apps.get(i); - updateExtraInfo(app, app.info.packageName, app.info.uid); - } - } - - @Override - protected void updateExtraInfo(AppEntry app, String pkg, int uid) { - app.extraInfo = isPackageQuarantined(pkg, uid); - } - - private boolean isPackageQuarantined(String pkg, int uid) { - final PackageManager pm = mContext.createContextAsUser( - UserHandle.getUserHandleForUid(uid), 0).getPackageManager(); - try { - return pm.isPackageQuarantined(pkg); - } catch (PackageManager.NameNotFoundException e) { - return false; - } - } -} diff --git a/src/com/android/settings/development/quarantine/QuarantinedAppsFragment.java b/src/com/android/settings/development/quarantine/QuarantinedAppsFragment.java deleted file mode 100644 index 985e96287de..00000000000 --- a/src/com/android/settings/development/quarantine/QuarantinedAppsFragment.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright (C) 2023 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.development.quarantine; - -import static android.view.MenuItem.SHOW_AS_ACTION_ALWAYS; -import static android.view.MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW; - -import android.app.settings.SettingsEnums; -import android.os.Bundle; -import android.text.TextUtils; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.widget.SearchView; - -import com.android.settings.R; -import com.android.settings.dashboard.DashboardFragment; -import com.android.settings.search.BaseSearchIndexProvider; -import com.android.settingslib.applications.AppIconCacheManager; -import com.android.settingslib.applications.ApplicationsState; -import com.android.settingslib.applications.ApplicationsState.AppFilter; -import com.android.settingslib.search.SearchIndexable; - -import com.google.android.material.appbar.AppBarLayout; - -// TODO: b/297934650 - Update this to use SPA framework -@SearchIndexable -public class QuarantinedAppsFragment extends DashboardFragment implements - SearchView.OnQueryTextListener, SearchView.OnCloseListener, - MenuItem.OnActionExpandListener { - private static final String TAG = "QuarantinedApps"; - - private static final int MENU_SEARCH_APPS = Menu.FIRST + 42; - private static final int MENU_SHOW_SYSTEM = Menu.FIRST + 43; - private static final String EXTRA_SHOW_SYSTEM = "show_system"; - - private boolean mShowSystem; - private SearchView mSearchView; - private String mCurQuery; - - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - mShowSystem = icicle != null && icicle.getBoolean(EXTRA_SHOW_SYSTEM); - use(QuarantinedAppsScreenController.class).setFilter(mCustomFilter); - use(QuarantinedAppsScreenController.class).setSession(getSettingsLifecycle()); - } - - @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { - mSearchView = new SearchView(getContext()); - mSearchView.setOnQueryTextListener(this); - mSearchView.setOnCloseListener(this); - mSearchView.setIconifiedByDefault(true); - - menu.add(Menu.NONE, MENU_SEARCH_APPS, Menu.NONE, R.string.search_settings) - .setIcon(R.drawable.ic_find_in_page_24px) - .setActionView(mSearchView) - .setOnActionExpandListener(this) - .setShowAsAction(SHOW_AS_ACTION_ALWAYS | SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW); - menu.add(Menu.NONE, MENU_SHOW_SYSTEM, Menu.NONE, - mShowSystem ? R.string.menu_hide_system : R.string.menu_show_system); - super.onCreateOptionsMenu(menu, inflater); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (item.getItemId() == MENU_SHOW_SYSTEM) { - mShowSystem = !mShowSystem; - item.setTitle(mShowSystem ? R.string.menu_hide_system : R.string.menu_show_system); - use(QuarantinedAppsScreenController.class).setFilter(mCustomFilter); - use(QuarantinedAppsScreenController.class).rebuild(); - return true; - } - return super.onOptionsItemSelected(item); - } - - @Override - public boolean onQueryTextChange(String newText) { - mCurQuery = !TextUtils.isEmpty(newText) ? newText : null; - use(QuarantinedAppsScreenController.class).rebuild(); - return true; - } - - @Override - public boolean onQueryTextSubmit(String query) { - // Don't care about this. - return true; - } - - @Override - public boolean onClose() { - if (!TextUtils.isEmpty(mSearchView.getQuery())) { - mSearchView.setQuery(null, true); - } - return true; - } - - public final AppFilter mCustomFilter = new AppFilter() { - @Override - public void init() { - } - - @Override - public boolean filterApp(ApplicationsState.AppEntry entry) { - final AppFilter defaultFilter = mShowSystem ? ApplicationsState.FILTER_ALL_ENABLED - : ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER; - return defaultFilter.filterApp(entry) && (mCurQuery == null - || entry.label.toLowerCase().contains(mCurQuery.toLowerCase())); - } - }; - - @Override - public boolean onMenuItemActionExpand(MenuItem item) { - final AppBarLayout mAppBarLayout = getActivity().findViewById(R.id.app_bar); - // To prevent a large space on tool bar. - mAppBarLayout.setExpanded(false /*expanded*/, false /*animate*/); - return true; - } - - @Override - public boolean onMenuItemActionCollapse(MenuItem item) { - final AppBarLayout mAppBarLayout = getActivity().findViewById(R.id.app_bar); - // To prevent a large space on tool bar. - mAppBarLayout.setExpanded(false /*expanded*/, false /*animate*/); - return true; - } - - @Override - public int getPreferenceScreenResId() { - return R.xml.quarantined_apps; - } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - outState.putBoolean(EXTRA_SHOW_SYSTEM, mShowSystem); - } - - @Override - protected String getLogTag() { - return TAG; - } - - @Override - public int getMetricsCategory() { - return SettingsEnums.QUARANTINED_APPS_DEV_CONTROL; - } - - @Override - public void onDestroyView() { - super.onDestroyView(); - AppIconCacheManager.getInstance().release(); - } - - public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = - new BaseSearchIndexProvider(R.xml.quarantined_apps); -} diff --git a/src/com/android/settings/development/quarantine/QuarantinedAppsPreferenceController.java b/src/com/android/settings/development/quarantine/QuarantinedAppsPreferenceController.java deleted file mode 100644 index de3b18bb3a6..00000000000 --- a/src/com/android/settings/development/quarantine/QuarantinedAppsPreferenceController.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2023 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.development.quarantine; - -import android.content.Context; -import android.content.pm.Flags; - -import com.android.settings.core.BasePreferenceController; - -public class QuarantinedAppsPreferenceController extends BasePreferenceController { - public QuarantinedAppsPreferenceController(Context context, String preferenceKey) { - super(context, preferenceKey); - } - - @Override - public int getAvailabilityStatus() { - return Flags.quarantinedEnabled() ? AVAILABLE : CONDITIONALLY_UNAVAILABLE; - } -} diff --git a/src/com/android/settings/development/quarantine/QuarantinedAppsScreenController.java b/src/com/android/settings/development/quarantine/QuarantinedAppsScreenController.java deleted file mode 100644 index 4d4834b6546..00000000000 --- a/src/com/android/settings/development/quarantine/QuarantinedAppsScreenController.java +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Copyright (C) 2023 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.development.quarantine; - -import android.app.Application; -import android.content.Context; -import android.content.pm.Flags; -import android.content.pm.PackageManager; -import android.content.pm.SuspendDialogInfo; -import android.os.UserHandle; - -import androidx.annotation.VisibleForTesting; -import androidx.preference.Preference; -import androidx.preference.PreferenceScreen; - -import com.android.settings.R; -import com.android.settings.applications.AppStateBaseBridge; -import com.android.settings.core.BasePreferenceController; -import com.android.settingslib.applications.AppUtils; -import com.android.settingslib.applications.ApplicationsState; -import com.android.settingslib.applications.ApplicationsState.AppEntry; -import com.android.settingslib.applications.ApplicationsState.AppFilter; -import com.android.settingslib.core.lifecycle.Lifecycle; -import com.android.settingslib.core.lifecycle.LifecycleObserver; -import com.android.settingslib.core.lifecycle.events.OnDestroy; -import com.android.settingslib.core.lifecycle.events.OnStart; -import com.android.settingslib.core.lifecycle.events.OnStop; - -import java.util.ArrayList; -import java.util.Set; -import java.util.TreeSet; - -public class QuarantinedAppsScreenController extends BasePreferenceController implements - LifecycleObserver, OnStart, OnStop, OnDestroy, - ApplicationsState.Callbacks, Preference.OnPreferenceChangeListener, - AppStateBaseBridge.Callback { - private final ApplicationsState mApplicationsState; - private final QuarantinedAppStateBridge mQuarantinedAppStateBridge; - private ApplicationsState.Session mSession; - private PreferenceScreen mScreen; - private AppFilter mFilter; - private boolean mExtraLoaded; - - public QuarantinedAppsScreenController(Context context, String preferenceKey) { - super(context, preferenceKey); - mApplicationsState = ApplicationsState.getInstance( - (Application) context.getApplicationContext()); - mQuarantinedAppStateBridge = new QuarantinedAppStateBridge(context, - mApplicationsState, this); - } - - @Override - public void onStart() { - mQuarantinedAppStateBridge.resume(true /* forceLoadAllApps */); - } - - @Override - public void onStop() { - mQuarantinedAppStateBridge.pause(); - } - - @Override - public void onDestroy() { - mQuarantinedAppStateBridge.release(); - } - - @Override - public void displayPreference(PreferenceScreen screen) { - super.displayPreference(screen); - mScreen = screen; - } - - public void setFilter(AppFilter filter) { - mFilter = filter; - } - - public void setSession(Lifecycle lifecycle) { - mSession = mApplicationsState.newSession(this, lifecycle); - } - - @Override - public void onExtraInfoUpdated() { - mExtraLoaded = true; - rebuild(); - } - - public void rebuild() { - if (!mExtraLoaded || mSession == null) { - return; - } - - final ArrayList apps = mSession.rebuild(mFilter, - ApplicationsState.ALPHA_COMPARATOR); - if (apps != null) { - onRebuildComplete(apps); - } - } - - @Override - public void onRebuildComplete(ArrayList apps) { - if (apps == null) { - return; - } - - // Preload top visible icons of app list. - AppUtils.preloadTopIcons(mContext, apps, - mContext.getResources().getInteger(R.integer.config_num_visible_app_icons)); - - // Create apps key set for removing useless preferences - final Set appsKeySet = new TreeSet<>(); - // Add or update preferences - final int count = apps.size(); - for (int i = 0; i < count; i++) { - final AppEntry entry = apps.get(i); - if (!shouldAddPreference(entry)) { - continue; - } - final String prefkey = QuarantinedAppPreference.generateKey(entry); - appsKeySet.add(prefkey); - QuarantinedAppPreference preference = mScreen.findPreference(prefkey); - if (preference == null) { - preference = new QuarantinedAppPreference(mScreen.getContext(), entry); - preference.setOnPreferenceChangeListener(this); - mScreen.addPreference(preference); - } else { - preference.updateState(); - } - preference.setOrder(i); - } - - // Remove useless preferences - removeUselessPrefs(appsKeySet); - } - - private void removeUselessPrefs(final Set appsKeySet) { - final int prefCount = mScreen.getPreferenceCount(); - String prefKey; - if (prefCount > 0) { - for (int i = prefCount - 1; i >= 0; i--) { - final Preference pref = mScreen.getPreference(i); - prefKey = pref.getKey(); - if (!appsKeySet.isEmpty() && appsKeySet.contains(prefKey)) { - continue; - } - mScreen.removePreference(pref); - } - } - } - - @VisibleForTesting - static boolean shouldAddPreference(AppEntry app) { - return app != null && UserHandle.isApp(app.info.uid); - } - - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - if (preference instanceof QuarantinedAppPreference) { - final QuarantinedAppPreference quarantinedPreference = - (QuarantinedAppPreference) preference; - final boolean quarantined = newValue == Boolean.TRUE; - setPackageQuarantined(quarantinedPreference.getEntry().info.packageName, - quarantinedPreference.getEntry().info.uid, quarantined); - quarantinedPreference.getEntry().extraInfo = quarantined; - return true; - } - return false; - } - - private void setPackageQuarantined(String pkg, int uid, boolean quarantined) { - final PackageManager pm = mContext.createContextAsUser( - UserHandle.getUserHandleForUid(uid), 0).getPackageManager(); - final SuspendDialogInfo dialogInfo; - if (quarantined) { - dialogInfo = new SuspendDialogInfo.Builder() - .setNeutralButtonText(R.string.unquarantine_app_button) - .setNeutralButtonAction(SuspendDialogInfo.BUTTON_ACTION_UNSUSPEND) - .build(); - } else { - dialogInfo = null; - } - pm.setPackagesSuspended(new String[] {pkg}, quarantined, null /* appExtras */, - null /* launcherExtras */, dialogInfo, - PackageManager.FLAG_SUSPEND_QUARANTINED); - } - - @Override - public int getAvailabilityStatus() { - return Flags.quarantinedEnabled() ? AVAILABLE : CONDITIONALLY_UNAVAILABLE; - } - - @Override - public void onRunningStateChanged(boolean running) { - } - - @Override - public void onPackageListChanged() { - } - - @Override - public void onPackageIconChanged() { - } - - @Override - public void onPackageSizeChanged(String packageName) { - } - - @Override - public void onAllSizesComputed() { - } - - @Override - public void onLauncherInfoChanged() { - } - - @Override - public void onLoadEntriesCompleted() { - } -} diff --git a/src/com/android/settings/enterprise/EnterprisePrivacyFeatureProviderImpl.java b/src/com/android/settings/enterprise/EnterprisePrivacyFeatureProviderImpl.java index 887fc3215a2..ef542a3590f 100644 --- a/src/com/android/settings/enterprise/EnterprisePrivacyFeatureProviderImpl.java +++ b/src/com/android/settings/enterprise/EnterprisePrivacyFeatureProviderImpl.java @@ -257,6 +257,7 @@ public class EnterprisePrivacyFeatureProviderImpl implements EnterprisePrivacyFe private boolean shouldSkipProfile(UserInfo userInfo) { return android.os.Flags.allowPrivateProfile() && android.multiuser.Flags.handleInterleavedSettingsForPrivateSpace() + && android.multiuser.Flags.enablePrivateSpaceFeatures() && userInfo.isQuietModeEnabled() && mUm.getUserProperties(userInfo.getUserHandle()).getShowInQuietMode() == UserProperties.SHOW_IN_QUIET_MODE_HIDDEN; diff --git a/src/com/android/settings/network/SimOnboardingActivity.kt b/src/com/android/settings/network/SimOnboardingActivity.kt index 98bb5d7a6db..350f5b8f9c1 100644 --- a/src/com/android/settings/network/SimOnboardingActivity.kt +++ b/src/com/android/settings/network/SimOnboardingActivity.kt @@ -21,7 +21,6 @@ import android.content.Intent import android.os.Bundle import android.telephony.SubscriptionManager import android.util.Log -import androidx.activity.compose.setContent import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth @@ -45,7 +44,6 @@ import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.MutableState -import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope @@ -67,7 +65,6 @@ import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle import com.android.settingslib.spa.widget.dialog.AlertDialogButton import com.android.settingslib.spa.widget.dialog.getDialogWidth import com.android.settingslib.spa.widget.dialog.rememberAlertDialogPresenter -import com.android.settingslib.spa.widget.editor.SettingsOutlinedTextField import com.android.settingslib.spa.widget.ui.SettingsTitle import com.android.settingslib.spaprivileged.framework.common.userManager import kotlinx.coroutines.CoroutineScope @@ -83,6 +80,8 @@ class SimOnboardingActivity : SpaBaseDialogActivity() { lateinit var showBottomSheet: MutableState lateinit var showError: MutableState lateinit var showProgressDialog: MutableState + lateinit var showDsdsProgressDialog: MutableState + lateinit var showRestartDialog: MutableState private var switchToEuiccSubscriptionSidecar: SwitchToEuiccSubscriptionSidecar? = null private var switchToRemovableSlotSidecar: SwitchToRemovableSlotSidecar? = null @@ -132,6 +131,12 @@ class SimOnboardingActivity : SpaBaseDialogActivity() { setProgressDialog(false) } + CallbackType.CALLBACK_ENABLE_DSDS-> { + scope.launch { + onboardingService.startEnableDsds(this@SimOnboardingActivity) + } + } + CallbackType.CALLBACK_ONBOARDING_COMPLETE -> { showBottomSheet.value = false setProgressDialog(true) @@ -179,12 +184,14 @@ class SimOnboardingActivity : SpaBaseDialogActivity() { showBottomSheet = remember { mutableStateOf(false) } showError = remember { mutableStateOf(ErrorType.ERROR_NONE) } showProgressDialog = remember { mutableStateOf(false) } + showDsdsProgressDialog = remember { mutableStateOf(false) } + showRestartDialog = remember { mutableStateOf(false) } scope = rememberCoroutineScope() registerSidecarReceiverFlow() ErrorDialogImpl() - + RestartDialogImpl() LaunchedEffect(Unit) { if (onboardingService.activeSubInfoList.isNotEmpty()) { showBottomSheet.value = true @@ -196,29 +203,76 @@ class SimOnboardingActivity : SpaBaseDialogActivity() { BottomSheetImpl( sheetState = sheetState, nextAction = { - // TODO: if the phone is SS mode and the isDsdsConditionSatisfied is true, then - // enable the DSDS mode. - // case#1: the device need the reboot after enabling DSDS. Showing the confirm - // dialog to user whether reboot device or not. - // case#2: The device don't need the reboot. Enabling DSDS and then showing - // the SIM onboarding UI. - - // case#2 - val route = getRoute(onboardingService.targetSubId) - startSpaActivity(route) + if (onboardingService.isDsdsConditionSatisfied()) { + // TODO: if the phone is SS mode and the isDsdsConditionSatisfied is true, + // then enable the DSDS mode. + // case#1: the device need the reboot after enabling DSDS. Showing the + // confirm dialog to user whether reboot device or not. + // case#2: The device don't need the reboot. Enabling DSDS and then showing + // the SIM onboarding UI. + if (onboardingService.doesSwitchMultiSimConfigTriggerReboot) { + // case#1 + Log.d(TAG, "Device does not support reboot free DSDS.") + showRestartDialog.value = true + } else { + // case#2 + Log.d(TAG, "Enable DSDS mode") + showDsdsProgressDialog.value = true + enableMultiSimSidecar?.run(SimOnboardingService.NUM_OF_SIMS_FOR_DSDS) + } + } else { + startSimOnboardingProvider() + } }, cancelAction = { finish() }, ) } - if(showProgressDialog.value) { - ProgressDialogImpl() + if (showProgressDialog.value) { + ProgressDialogImpl( + stringResource( + R.string.sim_onboarding_progressbar_turning_sim_on, + onboardingService.targetSubInfo?.displayName ?: "" + ) + ) + } + if (showDsdsProgressDialog.value) { + ProgressDialogImpl( + stringResource(R.string.sim_action_enabling_sim_without_carrier_name) + ) + } + } + @Composable + private fun RestartDialogImpl() { + val restartDialogPresenter = rememberAlertDialogPresenter( + confirmButton = AlertDialogButton( + stringResource(R.string.sim_action_reboot) + ) { + callbackListener(CallbackType.CALLBACK_ENABLE_DSDS) + }, + dismissButton = AlertDialogButton( + stringResource( + R.string.sim_action_restart_dialog_cancel, + onboardingService.targetSubInfo?.displayName ?: "") + ) { + callbackListener(CallbackType.CALLBACK_ONBOARDING_COMPLETE) + }, + title = stringResource(R.string.sim_action_restart_dialog_title), + text = { + Text(stringResource(R.string.sim_action_restart_dialog_msg)) + }, + ) + + if(showRestartDialog.value){ + LaunchedEffect(Unit) { + restartDialogPresenter.open() + } } } @OptIn(ExperimentalMaterial3Api::class) @Composable - fun ProgressDialogImpl() { + fun ProgressDialogImpl(title: String) { // TODO: Create the SPA's ProgressDialog and using SPA's widget BasicAlertDialog( onDismissRequest = {}, @@ -232,19 +286,14 @@ class SimOnboardingActivity : SpaBaseDialogActivity() { ) { Row( modifier = Modifier - .fillMaxWidth() - .padding(SettingsDimension.itemPaddingStart), + .fillMaxWidth() + .padding(SettingsDimension.itemPaddingStart), verticalAlignment = Alignment.CenterVertically ) { CircularProgressIndicator() Column(modifier = Modifier .padding(start = SettingsDimension.itemPaddingStart)) { - SettingsTitle( - stringResource( - R.string.sim_onboarding_progressbar_turning_sim_on, - onboardingService.targetSubInfo?.displayName ?: "" - ) - ) + SettingsTitle(title) } } } @@ -329,7 +378,7 @@ class SimOnboardingActivity : SpaBaseDialogActivity() { Log.e(TAG, "Error while sidecarReceiverFlow", e) }.conflate() - fun startSimSwitching(){ + fun startSimSwitching() { Log.d(TAG, "startSimSwitching:") var targetSubInfo = onboardingService.targetSubInfo @@ -376,8 +425,6 @@ class SimOnboardingActivity : SpaBaseDialogActivity() { switchToEuiccSubscriptionSidecar!!.reset() showError.value = ErrorType.ERROR_EUICC_SLOT callbackListener(CallbackType.CALLBACK_ERROR) - // TODO: showErrorDialog and using privileged_action_disable_fail_title and - // privileged_action_disable_fail_text } } } @@ -396,18 +443,19 @@ class SimOnboardingActivity : SpaBaseDialogActivity() { switchToRemovableSlotSidecar!!.reset() showError.value = ErrorType.ERROR_REMOVABLE_SLOT callbackListener(CallbackType.CALLBACK_ERROR) - // TODO: showErrorDialog and using sim_action_enable_sim_fail_title and - // sim_action_enable_sim_fail_text } } } fun handleEnableMultiSimSidecarStateChange() { + showDsdsProgressDialog.value = false when (enableMultiSimSidecar!!.state) { SidecarFragment.State.SUCCESS -> { enableMultiSimSidecar!!.reset() Log.i(TAG, "Successfully switched to DSDS without reboot.") - handleEnableSubscriptionAfterEnablingDsds() + // refresh data + initServiceData(this, onboardingService.targetSubId, callbackListener) + startSimOnboardingProvider() } SidecarFragment.State.ERROR -> { @@ -415,34 +463,14 @@ class SimOnboardingActivity : SpaBaseDialogActivity() { Log.i(TAG, "Failed to switch to DSDS without rebooting.") showError.value = ErrorType.ERROR_ENABLE_DSDS callbackListener(CallbackType.CALLBACK_ERROR) - // TODO: showErrorDialog and using dsds_activation_failure_title and - // dsds_activation_failure_body_msg2 } } } - fun handleEnableSubscriptionAfterEnablingDsds() { - var targetSubInfo = onboardingService.targetSubInfo - if (targetSubInfo?.isEmbedded == true) { - Log.i(TAG, - "DSDS enabled, start to enable profile: " + targetSubInfo.getSubscriptionId() - ) - // For eSIM operations, we simply switch to the selected eSIM profile. - switchToEuiccSubscriptionSidecar!!.run( - targetSubInfo.subscriptionId, - UiccSlotUtil.INVALID_PORT_ID, - null - ) - return - } - Log.i(TAG, "DSDS enabled, start to enable pSIM profile.") - onboardingService.handleTogglePsimAction() - callbackListener(CallbackType.CALLBACK_FINISH) - } - @Composable fun BottomSheetBody(nextAction: () -> Unit) { - Column(horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier.padding(bottom = SettingsDimension.itemPaddingVertical)) { + Column(horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier.padding(bottom = SettingsDimension.itemPaddingVertical)) { Icon( imageVector = Icons.Outlined.SignalCellularAlt, contentDescription = null, @@ -497,6 +525,11 @@ class SimOnboardingActivity : SpaBaseDialogActivity() { onboardingService.initData(targetSubId, context,callback) } + private fun startSimOnboardingProvider() { + val route = getRoute(onboardingService.targetSubId) + startSpaActivity(route) + } + companion object { @JvmStatic fun startSimOnboardingActivity( @@ -523,9 +556,10 @@ class SimOnboardingActivity : SpaBaseDialogActivity() { enum class CallbackType(val value:Int){ CALLBACK_ERROR(-1), CALLBACK_ONBOARDING_COMPLETE(1), - CALLBACK_SETUP_NAME(2), - CALLBACK_SETUP_PRIMARY_SIM(3), - CALLBACK_FINISH(4) + CALLBACK_ENABLE_DSDS(2), + CALLBACK_SETUP_NAME(3), + CALLBACK_SETUP_PRIMARY_SIM(4), + CALLBACK_FINISH(5) } } } \ No newline at end of file diff --git a/src/com/android/settings/network/SimOnboardingService.kt b/src/com/android/settings/network/SimOnboardingService.kt index 962741f2cd1..2ec1ad3ae43 100644 --- a/src/com/android/settings/network/SimOnboardingService.kt +++ b/src/com/android/settings/network/SimOnboardingService.kt @@ -24,6 +24,7 @@ import android.telephony.UiccCardInfo import android.telephony.UiccSlotInfo import android.util.Log import com.android.settings.network.SimOnboardingActivity.Companion.CallbackType +import com.android.settings.sim.SimActivationNotifier import com.android.settings.spa.network.setAutomaticData import com.android.settings.spa.network.setDefaultData import com.android.settings.spa.network.setDefaultSms @@ -32,9 +33,6 @@ import com.android.settingslib.utils.ThreadUtils import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext -private const val TAG = "SimOnboardingService" -private const val INVALID = SubscriptionManager.INVALID_SUBSCRIPTION_ID - class SimOnboardingService { var subscriptionManager:SubscriptionManager? = null var telephonyManager:TelephonyManager? = null @@ -70,7 +68,7 @@ class SimOnboardingService { } return uiccCardInfoList.any { it.isMultipleEnabledProfilesSupported } } - var isRemovableSimEnabled: Boolean = false + var isRemovablePsimProfileEnabled: Boolean = false get() { if(slotInfoList.isEmpty()) { Log.w(TAG, "UICC Slot info list is empty.") @@ -78,7 +76,11 @@ class SimOnboardingService { } return UiccSlotUtil.isRemovableSimEnabled(slotInfoList) } - + var isEsimProfileEnabled: Boolean = false + get() { + activeSubInfoList.stream().anyMatch { it.isEmbedded } + return false + } var doesTargetSimHaveEsimOperation = false get() { return targetSubInfo?.isEmbedded ?: false @@ -109,6 +111,19 @@ class SimOnboardingService { } return getActiveModemCount != 0 && activeSubInfoList.size == getActiveModemCount } + var isMultiSimEnabled = false + get() { + return getActiveModemCount > 1 + } + var isMultiSimSupported = false + get() { + return telephonyManager?.isMultiSimSupported == TelephonyManager.MULTISIM_ALLOWED + } + + var doesSwitchMultiSimConfigTriggerReboot = false + get() { + return telephonyManager?.doesSwitchMultiSimConfigTriggerReboot() ?: false + } fun isValid(): Boolean { return targetSubId != INVALID @@ -161,9 +176,10 @@ class SimOnboardingService { targetPrimarySimCalls = SubscriptionManager.getDefaultVoiceSubscriptionId() targetPrimarySimTexts = SubscriptionManager.getDefaultSmsSubscriptionId() targetPrimarySimMobileData = SubscriptionManager.getDefaultDataSubscriptionId() + Log.d( TAG,"doesTargetSimHaveEsimOperation: $doesTargetSimHaveEsimOperation" + - ", isRemovableSimEnabled: $isRemovableSimEnabled" + + ", isRemovableSimEnabled: $isRemovablePsimProfileEnabled" + ", isMultipleEnabledProfilesSupported: $isMultipleEnabledProfilesSupported" + ", targetPrimarySimCalls: $targetPrimarySimCalls" + ", targetPrimarySimTexts: $targetPrimarySimTexts" + @@ -261,6 +277,45 @@ class SimOnboardingService { } } + fun isDsdsConditionSatisfied(): Boolean { + if (isMultiSimEnabled) { + Log.d( + TAG, + "DSDS is already enabled. Condition not satisfied." + ) + return false + } + if (!isMultiSimSupported) { + Log.d(TAG, "Hardware does not support DSDS.") + return false + } + val isActiveSim = activeSubInfoList.isNotEmpty() + if (isMultipleEnabledProfilesSupported && isActiveSim) { + Log.d(TAG, + "Device supports MEP and eSIM operation and eSIM profile is enabled." + + " DSDS condition satisfied." + ) + return true + } + + if (doesTargetSimHaveEsimOperation && isRemovablePsimProfileEnabled) { + Log.d(TAG, + "eSIM operation and removable PSIM is enabled. DSDS condition satisfied." + ) + return true + } + + if (!doesTargetSimHaveEsimOperation && isEsimProfileEnabled) { + Log.d(TAG, + "Removable SIM operation and eSIM profile is enabled. DSDS condition" + + " satisfied." + ) + return true + } + Log.d(TAG, "DSDS condition not satisfied.") + return false + } + fun startActivatingSim(){ // TODO: start to activate sim callback(CallbackType.CALLBACK_FINISH) @@ -281,30 +336,50 @@ class SimOnboardingService { suspend fun startSetupPrimarySim(context: Context) { withContext(Dispatchers.Default) { - setDefaultVoice(subscriptionManager,targetPrimarySimCalls) - setDefaultSms(subscriptionManager,targetPrimarySimTexts) - setDefaultData( - context, - subscriptionManager, - null, - targetPrimarySimMobileData - ) + if (SubscriptionUtil.getActiveSubscriptions(subscriptionManager).size <= 1) { + Log.d(TAG, + "startSetupPrimarySim: number of active subscriptionInfo is less than 2" + ) + } else { + setDefaultVoice(subscriptionManager, targetPrimarySimCalls) + setDefaultSms(subscriptionManager, targetPrimarySimTexts) + setDefaultData( + context, + subscriptionManager, + null, + targetPrimarySimMobileData + ) - var nonDds = targetNonDds - Log.d( - TAG, - "setAutomaticData: targetNonDds: $nonDds," + - " targetPrimarySimAutoDataSwitch: $targetPrimarySimAutoDataSwitch" - ) - if (nonDds != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { - val telephonyManagerForNonDds: TelephonyManager? = - context.getSystemService(TelephonyManager::class.java) - ?.createForSubscriptionId(nonDds) - setAutomaticData(telephonyManagerForNonDds, targetPrimarySimAutoDataSwitch) + var nonDds = targetNonDds + Log.d( + TAG, + "setAutomaticData: targetNonDds: $nonDds," + + " targetPrimarySimAutoDataSwitch: $targetPrimarySimAutoDataSwitch" + ) + if (nonDds != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { + val telephonyManagerForNonDds: TelephonyManager? = + context.getSystemService(TelephonyManager::class.java) + ?.createForSubscriptionId(nonDds) + setAutomaticData(telephonyManagerForNonDds, targetPrimarySimAutoDataSwitch) + } } - // no next action, send finish callback(CallbackType.CALLBACK_FINISH) } } + + suspend fun startEnableDsds(context: Context) { + withContext(Dispatchers.Default) { + Log.d(TAG, "User confirmed reboot to enable DSDS.") + SimActivationNotifier.setShowSimSettingsNotification(context, true) + telephonyManager?.switchMultiSimConfig(NUM_OF_SIMS_FOR_DSDS) + callback(CallbackType.CALLBACK_FINISH) + } + } + + companion object{ + private const val TAG = "SimOnboardingService" + private const val INVALID = SubscriptionManager.INVALID_SUBSCRIPTION_ID + const val NUM_OF_SIMS_FOR_DSDS = 2 + } } \ No newline at end of file diff --git a/src/com/android/settings/network/SubscriptionInfoListViewModel.kt b/src/com/android/settings/network/SubscriptionInfoListViewModel.kt index f6820023c92..df3b8bad278 100644 --- a/src/com/android/settings/network/SubscriptionInfoListViewModel.kt +++ b/src/com/android/settings/network/SubscriptionInfoListViewModel.kt @@ -20,6 +20,7 @@ import android.app.Application import android.telephony.SubscriptionManager import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.viewModelScope +import com.android.settings.network.telephony.getSelectableSubscriptionInfoList import com.android.settings.network.telephony.subscriptionsChangedFlow import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.SharingStarted @@ -41,10 +42,10 @@ class SubscriptionInfoListViewModel(application: Application) : AndroidViewModel }.stateIn(scope, SharingStarted.Eagerly, initialValue = emptyList()) /** - * Getting the Selectable SubscriptionInfo List from the SubscriptionManager's + * Getting the Selectable SubscriptionInfo List from the SubscriptionRepository's * getAvailableSubscriptionInfoList */ val selectableSubscriptionInfoListFlow = application.subscriptionsChangedFlow().map { - SubscriptionUtil.getSelectableSubscriptionInfoList(application) + application.getSelectableSubscriptionInfoList() }.stateIn(scope, SharingStarted.Eagerly, initialValue = emptyList()) } diff --git a/src/com/android/settings/network/SubscriptionUtil.java b/src/com/android/settings/network/SubscriptionUtil.java index 83f6c389e79..497af25bb0b 100644 --- a/src/com/android/settings/network/SubscriptionUtil.java +++ b/src/com/android/settings/network/SubscriptionUtil.java @@ -50,12 +50,12 @@ import com.android.settings.network.helper.SelectableSubscriptions; import com.android.settings.network.helper.SubscriptionAnnotation; import com.android.settings.network.telephony.DeleteEuiccSubscriptionDialogActivity; import com.android.settings.network.telephony.EuiccRacConnectivityDialogActivity; +import com.android.settings.network.telephony.SubscriptionRepositoryKt; import com.android.settings.network.telephony.ToggleSubscriptionDialogActivity; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; -import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Locale; @@ -499,40 +499,7 @@ public class SubscriptionUtil { * @return list of user selectable subscriptions. */ public static List getSelectableSubscriptionInfoList(Context context) { - SubscriptionManager subManager = context.getSystemService(SubscriptionManager.class); - List availableList = subManager.getAvailableSubscriptionInfoList(); - if (availableList == null) { - return null; - } else { - // Multiple subscriptions in a group should only have one representative. - // It should be the current active primary subscription if any, or any - // primary subscription. - List selectableList = new ArrayList<>(); - Map groupMap = new HashMap<>(); - - for (SubscriptionInfo info : availableList) { - // Opportunistic subscriptions are considered invisible - // to users so they should never be returned. - if (!isSubscriptionVisible(subManager, context, info)) continue; - - ParcelUuid groupUuid = info.getGroupUuid(); - if (groupUuid == null) { - // Doesn't belong to any group. Add in the list. - selectableList.add(info); - } else if (!groupMap.containsKey(groupUuid) - || (groupMap.get(groupUuid).getSimSlotIndex() == INVALID_SIM_SLOT_INDEX - && info.getSimSlotIndex() != INVALID_SIM_SLOT_INDEX)) { - // If it belongs to a group that has never been recorded or it's the current - // active subscription, add it in the list. - selectableList.remove(groupMap.get(groupUuid)); - selectableList.add(info); - groupMap.put(groupUuid, info); - } - - } - Log.d(TAG, "getSelectableSubscriptionInfoList: " + selectableList); - return selectableList; - } + return SubscriptionRepositoryKt.getSelectableSubscriptionInfoList(context); } /** diff --git a/src/com/android/settings/network/telephony/CellInfoUtil.kt b/src/com/android/settings/network/telephony/CellInfoUtil.kt index c7b6b24b521..51f60e796ff 100644 --- a/src/com/android/settings/network/telephony/CellInfoUtil.kt +++ b/src/com/android/settings/network/telephony/CellInfoUtil.kt @@ -82,7 +82,7 @@ object CellInfoUtil { */ @JvmStatic fun cellInfoListToString(cellInfos: List): String = - cellInfos.joinToString { cellInfo -> cellInfo.readableString() } + cellInfos.joinToString(System.lineSeparator()) { cellInfo -> cellInfo.readableString() } /** * Convert [CellInfo] to a readable string without sensitive info. diff --git a/src/com/android/settings/network/telephony/MobileNetworkSwitchController.java b/src/com/android/settings/network/telephony/MobileNetworkSwitchController.java deleted file mode 100644 index 20a3d8921f7..00000000000 --- a/src/com/android/settings/network/telephony/MobileNetworkSwitchController.java +++ /dev/null @@ -1,147 +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.network.telephony; - -import static android.telephony.TelephonyManager.CALL_STATE_IDLE; - -import static androidx.lifecycle.Lifecycle.Event.ON_PAUSE; -import static androidx.lifecycle.Lifecycle.Event.ON_RESUME; - -import android.content.Context; -import android.telephony.SubscriptionInfo; -import android.telephony.SubscriptionManager; -import android.telephony.TelephonyCallback; -import android.telephony.TelephonyManager; - -import androidx.lifecycle.LifecycleObserver; -import androidx.lifecycle.OnLifecycleEvent; -import androidx.preference.PreferenceScreen; - -import com.android.settings.core.BasePreferenceController; -import com.android.settings.network.SubscriptionUtil; -import com.android.settings.network.SubscriptionsChangeListener; -import com.android.settings.widget.SettingsMainSwitchPreference; - -/** This controls a switch to allow enabling/disabling a mobile network */ -public class MobileNetworkSwitchController extends BasePreferenceController implements - SubscriptionsChangeListener.SubscriptionsChangeListenerClient, LifecycleObserver { - private static final String TAG = "MobileNetworkSwitchCtrl"; - private SettingsMainSwitchPreference mSwitchBar; - private int mSubId; - private SubscriptionsChangeListener mChangeListener; - private SubscriptionManager mSubscriptionManager; - private TelephonyManager mTelephonyManager; - private CallStateTelephonyCallback mCallStateCallback; - - public MobileNetworkSwitchController(Context context, String preferenceKey) { - super(context, preferenceKey); - mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; - mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class); - mTelephonyManager = mContext.getSystemService(TelephonyManager.class); - mChangeListener = new SubscriptionsChangeListener(context, this); - } - - void init(int subId) { - mSubId = subId; - mTelephonyManager = mTelephonyManager.createForSubscriptionId(mSubId); - } - - @OnLifecycleEvent(ON_RESUME) - public void onResume() { - mChangeListener.start(); - - if (mCallStateCallback == null) { - mCallStateCallback = new CallStateTelephonyCallback(); - mTelephonyManager.registerTelephonyCallback( - mContext.getMainExecutor(), mCallStateCallback); - } - update(); - } - - @OnLifecycleEvent(ON_PAUSE) - public void onPause() { - if (mCallStateCallback != null) { - mTelephonyManager.unregisterTelephonyCallback(mCallStateCallback); - mCallStateCallback = null; - } - mChangeListener.stop(); - } - - @Override - public void displayPreference(PreferenceScreen screen) { - super.displayPreference(screen); - mSwitchBar = (SettingsMainSwitchPreference) screen.findPreference(mPreferenceKey); - - mSwitchBar.setOnBeforeCheckedChangeListener((isChecked) -> { - // TODO b/135222940: re-evaluate whether to use - // mSubscriptionManager#isSubscriptionEnabled - if (mSubscriptionManager.isActiveSubscriptionId(mSubId) != isChecked) { - SubscriptionUtil.startToggleSubscriptionDialogActivity(mContext, mSubId, isChecked); - return true; - } - return false; - }); - update(); - } - - private void update() { - if (mSwitchBar == null) { - return; - } - - SubscriptionInfo subInfo = null; - for (SubscriptionInfo info : SubscriptionUtil.getAvailableSubscriptions(mContext)) { - if (info.getSubscriptionId() == mSubId) { - subInfo = info; - break; - } - } - - // For eSIM, we always want the toggle. If telephony stack support disabling a pSIM - // directly, we show the toggle. - if (subInfo == null || (!subInfo.isEmbedded() && !SubscriptionUtil.showToggleForPhysicalSim( - mSubscriptionManager))) { - mSwitchBar.hide(); - } else { - mSwitchBar.show(); - mSwitchBar.setCheckedInternal(mSubscriptionManager.isActiveSubscriptionId(mSubId)); - } - } - - @Override - public int getAvailabilityStatus() { - return AVAILABLE_UNSEARCHABLE; - - } - - @Override - public void onAirplaneModeChanged(boolean airplaneModeEnabled) { - } - - @Override - public void onSubscriptionsChanged() { - update(); - } - - private class CallStateTelephonyCallback extends TelephonyCallback implements - TelephonyCallback.CallStateListener { - @Override - public void onCallStateChanged(int state) { - mSwitchBar.setSwitchBarEnabled(state == CALL_STATE_IDLE); - } - } -} diff --git a/src/com/android/settings/network/telephony/MobileNetworkSwitchController.kt b/src/com/android/settings/network/telephony/MobileNetworkSwitchController.kt new file mode 100644 index 00000000000..dcac74fce6b --- /dev/null +++ b/src/com/android/settings/network/telephony/MobileNetworkSwitchController.kt @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2024 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.network.telephony + +import android.content.Context +import android.telephony.SubscriptionManager +import android.telephony.TelephonyManager +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.android.settings.R +import com.android.settings.network.SubscriptionUtil +import com.android.settings.spa.preference.ComposePreferenceController +import com.android.settingslib.spa.widget.preference.MainSwitchPreference +import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel +import kotlinx.coroutines.flow.map + +class MobileNetworkSwitchController @JvmOverloads constructor( + context: Context, + preferenceKey: String, + private val subscriptionRepository: SubscriptionRepository = SubscriptionRepository(context), +) : ComposePreferenceController(context, preferenceKey) { + + private var subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID + + override fun getAvailabilityStatus() = AVAILABLE_UNSEARCHABLE + + fun init(subId: Int) { + this.subId = subId + } + + @Composable + override fun Content() { + val context = LocalContext.current + if (remember { !context.isVisible() }) return + val checked by remember { + subscriptionRepository.isSubscriptionEnabledFlow(subId) + }.collectAsStateWithLifecycle(initialValue = null) + val changeable by remember { + context.callStateFlow(subId).map { it == TelephonyManager.CALL_STATE_IDLE } + }.collectAsStateWithLifecycle(initialValue = true) + MainSwitchPreference(model = object : SwitchPreferenceModel { + override val title = stringResource(R.string.mobile_network_use_sim_on) + override val changeable = { changeable } + override val checked = { checked } + override val onCheckedChange = { newChecked: Boolean -> + SubscriptionUtil.startToggleSubscriptionDialogActivity(mContext, subId, newChecked) + } + }) + } + + private fun Context.isVisible(): Boolean { + val subInfo = subscriptionRepository.getSelectableSubscriptionInfoList() + .firstOrNull { it.subscriptionId == subId } + ?: return false + // For eSIM, we always want the toggle. If telephony stack support disabling a pSIM + // directly, we show the toggle. + return subInfo.isEmbedded || requireSubscriptionManager().canDisablePhysicalSubscription() + } +} diff --git a/src/com/android/settings/network/telephony/NetworkScanHelper.java b/src/com/android/settings/network/telephony/NetworkScanHelper.java deleted file mode 100644 index 19613291231..00000000000 --- a/src/com/android/settings/network/telephony/NetworkScanHelper.java +++ /dev/null @@ -1,346 +0,0 @@ -/* - * Copyright (C) 2018 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.network.telephony; - -import android.annotation.IntDef; -import android.content.Context; -import android.telephony.AccessNetworkConstants.AccessNetworkType; -import android.telephony.CellInfo; -import android.telephony.NetworkScan; -import android.telephony.NetworkScanRequest; -import android.telephony.PhoneCapability; -import android.telephony.RadioAccessSpecifier; -import android.telephony.TelephonyManager; -import android.telephony.TelephonyScanManager; -import android.util.Log; - -import androidx.annotation.VisibleForTesting; - -import com.android.internal.telephony.CellNetworkScanResult; - -import com.android.settings.R; - -import com.google.common.util.concurrent.FutureCallback; -import com.google.common.util.concurrent.Futures; -import com.google.common.util.concurrent.ListenableFuture; -import com.google.common.util.concurrent.MoreExecutors; -import com.google.common.util.concurrent.SettableFuture; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.concurrent.CancellationException; -import java.util.concurrent.Executor; -import java.util.stream.Collectors; - -/** - * A helper class that builds the common interface and performs the network scan for two different - * network scan APIs. - */ -public class NetworkScanHelper { - public static final String TAG = "NetworkScanHelper"; - - /** - * Callbacks interface to inform the network scan results. - */ - public interface NetworkScanCallback { - /** - * Called when the results is returned from {@link TelephonyManager}. This method will be - * called at least one time if there is no error occurred during the network scan. - * - *

This method can be called multiple times in one network scan, until - * {@link #onComplete()} or {@link #onError(int)} is called. - * - * @param results - */ - void onResults(List results); - - /** - * Called when the current network scan process is finished. No more - * {@link #onResults(List)} will be called for the current network scan after this method is - * called. - */ - void onComplete(); - - /** - * Called when an error occurred during the network scan process. - * - *

There is no more result returned from {@link TelephonyManager} if an error occurred. - * - *

{@link #onComplete()} will not be called if an error occurred. - * - * @see {@link NetworkScan.ScanErrorCode} - */ - void onError(int errorCode); - } - - @Retention(RetentionPolicy.SOURCE) - @IntDef({NETWORK_SCAN_TYPE_WAIT_FOR_ALL_RESULTS, NETWORK_SCAN_TYPE_INCREMENTAL_RESULTS}) - public @interface NetworkQueryType {} - - /** - * Performs the network scan using {@link TelephonyManager#getAvailableNetworks()}. The network - * scan results won't be returned to the caller until the network scan is completed. - * - *

This is typically used when the modem doesn't support the new network scan api - * {@link TelephonyManager#requestNetworkScan( - * NetworkScanRequest, Executor, TelephonyScanManager.NetworkScanCallback)}. - */ - public static final int NETWORK_SCAN_TYPE_WAIT_FOR_ALL_RESULTS = 1; - - /** - * Performs the network scan using {@link TelephonyManager#requestNetworkScan( - * NetworkScanRequest, Executor, TelephonyScanManager.NetworkScanCallback)} The network scan - * results will be returned to the caller periodically in a small time window until the network - * scan is completed. The complete results should be returned in the last called of - * {@link NetworkScanCallback#onResults(List)}. - * - *

This is recommended to be used if modem supports the new network scan api - * {@link TelephonyManager#requestNetworkScan( - * NetworkScanRequest, Executor, TelephonyScanManager.NetworkScanCallback)} - */ - public static final int NETWORK_SCAN_TYPE_INCREMENTAL_RESULTS = 2; - - /** The constants below are used in the async network scan. */ - @VisibleForTesting - static final boolean INCREMENTAL_RESULTS = true; - @VisibleForTesting - static final int SEARCH_PERIODICITY_SEC = 5; - @VisibleForTesting - static final int MAX_SEARCH_TIME_SEC = 300; - @VisibleForTesting - static final int INCREMENTAL_RESULTS_PERIODICITY_SEC = 3; - - private final NetworkScanCallback mNetworkScanCallback; - private final TelephonyManager mTelephonyManager; - private final TelephonyScanManager.NetworkScanCallback mInternalNetworkScanCallback; - private final Executor mExecutor; - - private int mMaxSearchTimeSec = MAX_SEARCH_TIME_SEC; - private NetworkScan mNetworkScanRequester; - - /** Callbacks for sync network scan */ - private ListenableFuture> mNetworkScanFuture; - - public NetworkScanHelper(TelephonyManager tm, NetworkScanCallback callback, Executor executor) { - mTelephonyManager = tm; - mNetworkScanCallback = callback; - mInternalNetworkScanCallback = new NetworkScanCallbackImpl(); - mExecutor = executor; - } - - public NetworkScanHelper(Context context, TelephonyManager tm, NetworkScanCallback callback, - Executor executor) { - this(tm, callback, executor); - mMaxSearchTimeSec = context.getResources().getInteger( - R.integer.config_network_scan_helper_max_search_time_sec); - } - - @VisibleForTesting - NetworkScanRequest createNetworkScanForPreferredAccessNetworks() { - long networkTypeBitmap3gpp = mTelephonyManager.getPreferredNetworkTypeBitmask() - & TelephonyManager.NETWORK_STANDARDS_FAMILY_BITMASK_3GPP; - - List radioAccessSpecifiers = new ArrayList<>(); - // If the allowed network types are unknown or if they are of the right class, scan for - // them; otherwise, skip them to save scan time and prevent users from being shown networks - // that they can't connect to. - if (networkTypeBitmap3gpp == 0 - || (networkTypeBitmap3gpp & TelephonyManager.NETWORK_CLASS_BITMASK_2G) != 0) { - radioAccessSpecifiers.add( - new RadioAccessSpecifier(AccessNetworkType.GERAN, null, null)); - } - if (networkTypeBitmap3gpp == 0 - || (networkTypeBitmap3gpp & TelephonyManager.NETWORK_CLASS_BITMASK_3G) != 0) { - radioAccessSpecifiers.add( - new RadioAccessSpecifier(AccessNetworkType.UTRAN, null, null)); - } - if (networkTypeBitmap3gpp == 0 - || (networkTypeBitmap3gpp & TelephonyManager.NETWORK_CLASS_BITMASK_4G) != 0) { - radioAccessSpecifiers.add( - new RadioAccessSpecifier(AccessNetworkType.EUTRAN, null, null)); - } - // If a device supports 5G stand-alone then the code below should be re-enabled; however - // a device supporting only non-standalone mode cannot perform PLMN selection and camp on - // a 5G network, which means that it shouldn't scan for 5G at the expense of battery as - // part of the manual network selection process. - // - if (networkTypeBitmap3gpp == 0 - || (hasNrSaCapability() - && (networkTypeBitmap3gpp & TelephonyManager.NETWORK_CLASS_BITMASK_5G) != 0)) { - radioAccessSpecifiers.add( - new RadioAccessSpecifier(AccessNetworkType.NGRAN, null, null)); - Log.d(TAG, "radioAccessSpecifiers add NGRAN."); - } - - return new NetworkScanRequest( - NetworkScanRequest.SCAN_TYPE_ONE_SHOT, - radioAccessSpecifiers.toArray( - new RadioAccessSpecifier[radioAccessSpecifiers.size()]), - SEARCH_PERIODICITY_SEC, - mMaxSearchTimeSec, - INCREMENTAL_RESULTS, - INCREMENTAL_RESULTS_PERIODICITY_SEC, - null /* List of PLMN ids (MCC-MNC) */); - } - - /** - * Performs a network scan for the given type {@code type}. - * {@link #NETWORK_SCAN_TYPE_INCREMENTAL_RESULTS} is recommended if modem supports - * {@link TelephonyManager#requestNetworkScan( - * NetworkScanRequest, Executor, TelephonyScanManager.NetworkScanCallback)}. - * - * @param type used to tell which network scan API should be used. - */ - public void startNetworkScan(@NetworkQueryType int type) { - if (type == NETWORK_SCAN_TYPE_WAIT_FOR_ALL_RESULTS) { - mNetworkScanFuture = SettableFuture.create(); - Futures.addCallback(mNetworkScanFuture, new FutureCallback>() { - @Override - public void onSuccess(List result) { - onResults(result); - onComplete(); - } - - @Override - public void onFailure(Throwable t) { - if (t instanceof CancellationException) { - return; - } - int errCode = Integer.parseInt(t.getMessage()); - onError(errCode); - } - }, MoreExecutors.directExecutor()); - mExecutor.execute(new NetworkScanSyncTask( - mTelephonyManager, (SettableFuture) mNetworkScanFuture)); - } else if (type == NETWORK_SCAN_TYPE_INCREMENTAL_RESULTS) { - if (mNetworkScanRequester != null) { - return; - } - mNetworkScanRequester = mTelephonyManager.requestNetworkScan( - createNetworkScanForPreferredAccessNetworks(), - mExecutor, - mInternalNetworkScanCallback); - if (mNetworkScanRequester == null) { - onError(NetworkScan.ERROR_RADIO_INTERFACE_ERROR); - } - } - } - - /** - * The network scan of type {@link #NETWORK_SCAN_TYPE_WAIT_FOR_ALL_RESULTS} can't be stopped, - * however, the result of the current network scan won't be returned to the callback after - * calling this method. - */ - public void stopNetworkQuery() { - if (mNetworkScanRequester != null) { - mNetworkScanRequester.stopScan(); - mNetworkScanRequester = null; - } - - if (mNetworkScanFuture != null) { - mNetworkScanFuture.cancel(true /* mayInterruptIfRunning */); - mNetworkScanFuture = null; - } - } - - private void onResults(List cellInfos) { - mNetworkScanCallback.onResults(cellInfos); - } - - private void onComplete() { - mNetworkScanCallback.onComplete(); - } - - private void onError(int errCode) { - mNetworkScanCallback.onError(errCode); - } - - private boolean hasNrSaCapability() { - return Arrays.stream( - mTelephonyManager.getPhoneCapability().getDeviceNrCapabilities()) - .anyMatch(i -> i == PhoneCapability.DEVICE_NR_CAPABILITY_SA); - } - - /** - * Converts the status code of {@link CellNetworkScanResult} to one of the - * {@link NetworkScan.ScanErrorCode}. - * @param errCode status code from {@link CellNetworkScanResult}. - * - * @return one of the scan error code from {@link NetworkScan.ScanErrorCode}. - */ - private static int convertToScanErrorCode(int errCode) { - switch (errCode) { - case CellNetworkScanResult.STATUS_RADIO_NOT_AVAILABLE: - return NetworkScan.ERROR_RADIO_INTERFACE_ERROR; - case CellNetworkScanResult.STATUS_RADIO_GENERIC_FAILURE: - default: - return NetworkScan.ERROR_MODEM_ERROR; - } - } - - private final class NetworkScanCallbackImpl extends TelephonyScanManager.NetworkScanCallback { - public void onResults(List results) { - Log.d(TAG, "Async scan onResults() results = " - + CellInfoUtil.cellInfoListToString(results)); - NetworkScanHelper.this.onResults(results); - } - - public void onComplete() { - Log.d(TAG, "async scan onComplete()"); - NetworkScanHelper.this.onComplete(); - } - - public void onError(@NetworkScan.ScanErrorCode int errCode) { - Log.d(TAG, "async scan onError() errorCode = " + errCode); - NetworkScanHelper.this.onError(errCode); - } - } - - private static final class NetworkScanSyncTask implements Runnable { - private final SettableFuture> mCallback; - private final TelephonyManager mTelephonyManager; - - NetworkScanSyncTask( - TelephonyManager telephonyManager, SettableFuture> callback) { - mTelephonyManager = telephonyManager; - mCallback = callback; - } - - @Override - public void run() { - final CellNetworkScanResult result = mTelephonyManager.getAvailableNetworks(); - if (result.getStatus() == CellNetworkScanResult.STATUS_SUCCESS) { - final List cellInfos = result.getOperators() - .stream() - .map(operatorInfo - -> CellInfoUtil.convertOperatorInfoToCellInfo(operatorInfo)) - .collect(Collectors.toList()); - Log.d(TAG, "Sync network scan completed, cellInfos = " - + CellInfoUtil.cellInfoListToString(cellInfos)); - mCallback.set(cellInfos); - } else { - final Throwable error = new Throwable( - Integer.toString(convertToScanErrorCode(result.getStatus()))); - mCallback.setException(error); - Log.d(TAG, "Sync network scan error, ex = " + error); - } - } - } -} diff --git a/src/com/android/settings/network/telephony/NetworkSelectSettings.java b/src/com/android/settings/network/telephony/NetworkSelectSettings.java index 461930b9e81..eb89d9ef95c 100644 --- a/src/com/android/settings/network/telephony/NetworkSelectSettings.java +++ b/src/com/android/settings/network/telephony/NetworkSelectSettings.java @@ -16,7 +16,6 @@ package com.android.settings.network.telephony; -import android.app.Activity; import android.app.settings.SettingsEnums; import android.content.Context; import android.content.Intent; @@ -39,6 +38,7 @@ import android.util.Log; import android.view.View; import androidx.annotation.Keep; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import androidx.preference.Preference; @@ -48,14 +48,21 @@ import com.android.internal.annotations.Initializer; import com.android.internal.telephony.OperatorInfo; import com.android.settings.R; import com.android.settings.dashboard.DashboardFragment; +import com.android.settings.network.telephony.scan.NetworkScanRepository; +import com.android.settings.network.telephony.scan.NetworkScanRepository.NetworkScanCellInfos; +import com.android.settings.network.telephony.scan.NetworkScanRepository.NetworkScanComplete; +import com.android.settings.network.telephony.scan.NetworkScanRepository.NetworkScanError; +import com.android.settings.network.telephony.scan.NetworkScanRepository.NetworkScanResult; import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.utils.ThreadUtils; +import kotlin.Unit; +import kotlin.jvm.functions.Function1; + import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.Optional; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicBoolean; @@ -70,12 +77,8 @@ public class NetworkSelectSettings extends DashboardFragment { private static final String TAG = "NetworkSelectSettings"; private static final int EVENT_SET_NETWORK_SELECTION_MANUALLY_DONE = 1; - private static final int EVENT_NETWORK_SCAN_RESULTS = 2; - private static final int EVENT_NETWORK_SCAN_ERROR = 3; - private static final int EVENT_NETWORK_SCAN_COMPLETED = 4; private static final String PREF_KEY_NETWORK_OPERATORS = "network_operators_preference"; - private static final int MIN_NUMBER_OF_SCAN_REQUIRED = 2; private PreferenceCategory mPreferenceCategory; @VisibleForTesting @@ -90,18 +93,14 @@ public class NetworkSelectSettings extends DashboardFragment { private CarrierConfigManager mCarrierConfigManager; private List mForbiddenPlmns; private boolean mShow4GForLTE = false; - private NetworkScanHelper mNetworkScanHelper; private final ExecutorService mNetworkScanExecutor = Executors.newFixedThreadPool(1); private MetricsFeatureProvider mMetricsFeatureProvider; - private boolean mUseNewApi; - private long mRequestIdManualNetworkSelect; - private long mRequestIdManualNetworkScan; - private long mWaitingForNumberOfScanResults; - @VisibleForTesting - boolean mIsAggregationEnabled = false; private CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener; private AtomicBoolean mShouldFilterOutSatellitePlmn = new AtomicBoolean(); + private NetworkScanRepository mNetworkScanRepository; + private boolean mUpdateScanResult = false; + @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); @@ -113,7 +112,6 @@ public class NetworkSelectSettings extends DashboardFragment { @Initializer protected void onCreateInitialization() { Context context = getContext(); - mUseNewApi = enableNewAutoSelectNetworkUI(context); mSubId = getSubId(); mPreferenceCategory = getPreferenceCategory(PREF_KEY_NETWORK_OPERATORS); @@ -123,8 +121,6 @@ public class NetworkSelectSettings extends DashboardFragment { mTelephonyManager = getTelephonyManager(context, mSubId); mSatelliteManager = getSatelliteManager(context); mCarrierConfigManager = getCarrierConfigManager(context); - mNetworkScanHelper = new NetworkScanHelper( - mTelephonyManager, mCallback, mNetworkScanExecutor); PersistableBundle bundle = mCarrierConfigManager.getConfigForSubId(mSubId, CarrierConfigManager.KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL, CarrierConfigManager.KEY_REMOVE_SATELLITE_PLMN_IN_MANUAL_NETWORK_SCAN_BOOL); @@ -135,30 +131,13 @@ public class NetworkSelectSettings extends DashboardFragment { true)); mMetricsFeatureProvider = getMetricsFeatureProvider(context); - mIsAggregationEnabled = enableAggregation(context); - Log.d(TAG, "init: mUseNewApi:" + mUseNewApi - + " ,mIsAggregationEnabled:" + mIsAggregationEnabled + " ,mSubId:" + mSubId); mCarrierConfigChangeListener = (slotIndex, subId, carrierId, specificCarrierId) -> handleCarrierConfigChanged( subId); mCarrierConfigManager.registerCarrierConfigChangeListener(mNetworkScanExecutor, mCarrierConfigChangeListener); - - } - - @Keep - @VisibleForTesting - protected boolean enableNewAutoSelectNetworkUI(Context context) { - return context.getResources().getBoolean( - com.android.internal.R.bool.config_enableNewAutoSelectNetworkUI); - } - - @Keep - @VisibleForTesting - protected boolean enableAggregation(Context context) { - return context.getResources().getBoolean( - R.bool.config_network_selection_list_aggregation_enabled); + mNetworkScanRepository = new NetworkScanRepository(context, mSubId); } @Keep @@ -217,17 +196,42 @@ public class NetworkSelectSettings extends DashboardFragment { } @Override - public void onViewCreated(View view, Bundle savedInstanceState) { + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); - final Activity activity = getActivity(); - if (activity != null) { - mProgressHeader = setPinnedHeaderView( - com.android.settingslib.widget.progressbar.R.layout.progress_header) - .findViewById(com.android.settingslib.widget.progressbar.R.id.progress_bar_animation); - setProgressBarVisible(false); - } + mProgressHeader = setPinnedHeaderView( + com.android.settingslib.widget.progressbar.R.layout.progress_header + ).findViewById(com.android.settingslib.widget.progressbar.R.id.progress_bar_animation); forceUpdateConnectedPreferenceCategory(); + launchNetworkScan(); + } + + private void launchNetworkScan() { + mNetworkScanRepository.launchNetworkScan(getViewLifecycleOwner(), new Function1<>() { + @Override + public Unit invoke(@NonNull NetworkScanResult networkScanResult) { + if (!mUpdateScanResult) { + // Not update UI if not in scan mode. + return Unit.INSTANCE; + } + if (networkScanResult instanceof NetworkScanCellInfos networkScanCellInfos) { + scanResultHandler(networkScanCellInfos.getCellInfos()); + return Unit.INSTANCE; + } + if (!isPreferenceScreenEnabled()) { + clearPreferenceSummary(); + enablePreferenceScreen(true); + } else if (networkScanResult instanceof NetworkScanComplete + && mCellInfoList == null) { + // In case the scan timeout before getting any results + addMessagePreference(R.string.empty_networks_list); + } else if (networkScanResult instanceof NetworkScanError) { + addMessagePreference(R.string.network_query_error); + } + + return Unit.INSTANCE; + } + }); } @Override @@ -235,12 +239,8 @@ public class NetworkSelectSettings extends DashboardFragment { super.onStart(); updateForbiddenPlmns(); - if (isProgressBarVisible()) { - return; - } - if (mWaitingForNumberOfScanResults <= 0) { - startNetworkQuery(); - } + setProgressBarVisible(true); + mUpdateScanResult = true; } /** @@ -255,14 +255,6 @@ public class NetworkSelectSettings extends DashboardFragment { : new ArrayList<>(); } - @Override - public void onStop() { - if (mWaitingForNumberOfScanResults <= 0) { - stopNetworkQuery(); - } - super.onStop(); - } - @Override public boolean onPreferenceTreeClick(Preference preference) { if (preference == mSelectedPreference) { @@ -274,7 +266,7 @@ public class NetworkSelectSettings extends DashboardFragment { return false; } - stopNetworkQuery(); + mUpdateScanResult = false; // Refresh the last selected item in case users reselect network. clearPreferenceSummary(); @@ -293,8 +285,6 @@ public class NetworkSelectSettings extends DashboardFragment { // Disable the screen until network is manually set enablePreferenceScreen(false); - mRequestIdManualNetworkSelect = getNewRequestId(); - mWaitingForNumberOfScanResults = MIN_NUMBER_OF_SCAN_REQUIRED; final OperatorInfo operator = mSelectedPreference.getOperatorInfo(); ThreadUtils.postOnBackgroundThread(() -> { final Message msg = mHandler.obtainMessage( @@ -328,7 +318,6 @@ public class NetworkSelectSettings extends DashboardFragment { switch (msg.what) { case EVENT_SET_NETWORK_SELECTION_MANUALLY_DONE: final boolean isSucceed = (boolean) msg.obj; - stopNetworkQuery(); setProgressBarVisible(false); enablePreferenceScreen(true); @@ -340,86 +329,15 @@ public class NetworkSelectSettings extends DashboardFragment { Log.e(TAG, "No preference to update!"); } break; - case EVENT_NETWORK_SCAN_RESULTS: - scanResultHandler((List) msg.obj); - break; - - case EVENT_NETWORK_SCAN_ERROR: - stopNetworkQuery(); - Log.i(TAG, "Network scan failure " + msg.arg1 + ":" - + " scan request 0x" + Long.toHexString(mRequestIdManualNetworkScan) - + ", waiting for scan results = " + mWaitingForNumberOfScanResults - + ", select request 0x" - + Long.toHexString(mRequestIdManualNetworkSelect)); - if (mRequestIdManualNetworkScan < mRequestIdManualNetworkSelect) { - break; - } - if (!isPreferenceScreenEnabled()) { - clearPreferenceSummary(); - enablePreferenceScreen(true); - } else { - addMessagePreference(R.string.network_query_error); - } - break; - - case EVENT_NETWORK_SCAN_COMPLETED: - stopNetworkQuery(); - Log.d(TAG, "Network scan complete:" - + " scan request 0x" + Long.toHexString(mRequestIdManualNetworkScan) - + ", waiting for scan results = " + mWaitingForNumberOfScanResults - + ", select request 0x" - + Long.toHexString(mRequestIdManualNetworkSelect)); - if (mRequestIdManualNetworkScan < mRequestIdManualNetworkSelect) { - break; - } - if (!isPreferenceScreenEnabled()) { - clearPreferenceSummary(); - enablePreferenceScreen(true); - } else if (mCellInfoList == null) { - // In case the scan timeout before getting any results - addMessagePreference(R.string.empty_networks_list); - } - break; } - return; } }; - @VisibleForTesting - List doAggregation(List cellInfoListInput) { - if (!mIsAggregationEnabled) { - Log.d(TAG, "no aggregation"); - return new ArrayList<>(cellInfoListInput); - } - ArrayList aggregatedList = new ArrayList<>(); - for (CellInfo cellInfo : cellInfoListInput) { - String plmn = CellInfoUtil.getNetworkTitle(cellInfo.getCellIdentity()); - Class className = cellInfo.getClass(); - - Optional itemInTheList = aggregatedList.stream().filter( - item -> { - String itemPlmn = CellInfoUtil.getNetworkTitle(item.getCellIdentity()); - return itemPlmn.equals(plmn) && item.getClass().equals(className); - }) - .findFirst(); - if (itemInTheList.isPresent()) { - if (cellInfo.isRegistered() && !itemInTheList.get().isRegistered()) { - // Adding the registered cellinfo item into list. If there are two registered - // cellinfo items, then select first one from source list. - aggregatedList.set(aggregatedList.indexOf(itemInTheList.get()), cellInfo); - } - continue; - } - aggregatedList.add(cellInfo); - } - - return filterOutSatellitePlmn(aggregatedList); - } - /* We do not want to expose carrier satellite plmns to the user when manually scan the cellular network. Therefore, it is needed to filter out satellite plmns from current cell info list */ - private List filterOutSatellitePlmn(List cellInfoList) { + @VisibleForTesting + List filterOutSatellitePlmn(List cellInfoList) { List aggregatedSatellitePlmn = getSatellitePlmnsForCarrierWrapper(); if (!mShouldFilterOutSatellitePlmn.get() || aggregatedSatellitePlmn.isEmpty()) { return cellInfoList; @@ -451,39 +369,10 @@ public class NetworkSelectSettings extends DashboardFragment { } } - private final NetworkScanHelper.NetworkScanCallback mCallback = - new NetworkScanHelper.NetworkScanCallback() { - public void onResults(List results) { - final Message msg = mHandler.obtainMessage(EVENT_NETWORK_SCAN_RESULTS, results); - msg.sendToTarget(); - } - - public void onComplete() { - final Message msg = mHandler.obtainMessage(EVENT_NETWORK_SCAN_COMPLETED); - msg.sendToTarget(); - } - - public void onError(int error) { - final Message msg = mHandler.obtainMessage(EVENT_NETWORK_SCAN_ERROR, error, - 0 /* arg2 */); - msg.sendToTarget(); - } - }; - @Keep @VisibleForTesting protected void scanResultHandler(List results) { - if (mRequestIdManualNetworkScan < mRequestIdManualNetworkSelect) { - Log.d(TAG, "CellInfoList (drop): " - + CellInfoUtil.cellInfoListToString(new ArrayList<>(results))); - return; - } - mWaitingForNumberOfScanResults--; - if ((mWaitingForNumberOfScanResults <= 0) && (!isResumed())) { - stopNetworkQuery(); - } - - mCellInfoList = doAggregation(results); + mCellInfoList = filterOutSatellitePlmn(results); Log.d(TAG, "CellInfoList: " + CellInfoUtil.cellInfoListToString(mCellInfoList)); if (mCellInfoList != null && mCellInfoList.size() != 0) { final NetworkOperatorPreference connectedPref = updateAllPreferenceCategory(); @@ -642,11 +531,6 @@ public class NetworkSelectSettings extends DashboardFragment { } } - private long getNewRequestId() { - return Math.max(mRequestIdManualNetworkSelect, - mRequestIdManualNetworkScan) + 1; - } - private boolean isProgressBarVisible() { if (mProgressHeader == null) { return false; @@ -667,29 +551,8 @@ public class NetworkSelectSettings extends DashboardFragment { mPreferenceCategory.addPreference(mStatusMessagePreference); } - private void startNetworkQuery() { - setProgressBarVisible(true); - if (mNetworkScanHelper != null) { - mRequestIdManualNetworkScan = getNewRequestId(); - mWaitingForNumberOfScanResults = MIN_NUMBER_OF_SCAN_REQUIRED; - mNetworkScanHelper.startNetworkScan( - mUseNewApi - ? NetworkScanHelper.NETWORK_SCAN_TYPE_INCREMENTAL_RESULTS - : NetworkScanHelper.NETWORK_SCAN_TYPE_WAIT_FOR_ALL_RESULTS); - } - } - - private void stopNetworkQuery() { - setProgressBarVisible(false); - if (mNetworkScanHelper != null) { - mWaitingForNumberOfScanResults = 0; - mNetworkScanHelper.stopNetworkQuery(); - } - } - @Override public void onDestroy() { - stopNetworkQuery(); mNetworkScanExecutor.shutdown(); super.onDestroy(); } diff --git a/src/com/android/settings/network/telephony/SubscriptionRepository.kt b/src/com/android/settings/network/telephony/SubscriptionRepository.kt index e44b577de02..1da6a96489b 100644 --- a/src/com/android/settings/network/telephony/SubscriptionRepository.kt +++ b/src/com/android/settings/network/telephony/SubscriptionRepository.kt @@ -32,9 +32,24 @@ import kotlinx.coroutines.flow.onEach private const val TAG = "SubscriptionRepository" -fun Context.isSubscriptionEnabledFlow(subId: Int) = subscriptionsChangedFlow().map { - val subscriptionManager = getSystemService(SubscriptionManager::class.java) +class SubscriptionRepository(private val context: Context) { + /** + * Return a list of subscriptions that are available and visible to the user. + * + * @return list of user selectable subscriptions. + */ + fun getSelectableSubscriptionInfoList(): List = + context.getSelectableSubscriptionInfoList() + fun isSubscriptionEnabledFlow(subId: Int) = context.isSubscriptionEnabledFlow(subId) +} + +val Context.subscriptionManager: SubscriptionManager? + get() = getSystemService(SubscriptionManager::class.java) + +fun Context.requireSubscriptionManager(): SubscriptionManager = subscriptionManager!! + +fun Context.isSubscriptionEnabledFlow(subId: Int) = subscriptionsChangedFlow().map { subscriptionManager?.isSubscriptionEnabled(subId) ?: false }.flowOn(Dispatchers.Default) @@ -43,7 +58,7 @@ fun Context.phoneNumberFlow(subscriptionInfo: SubscriptionInfo) = subscriptionsC }.flowOn(Dispatchers.Default) fun Context.subscriptionsChangedFlow() = callbackFlow { - val subscriptionManager = getSystemService(SubscriptionManager::class.java)!! + val subscriptionManager = requireSubscriptionManager() val listener = object : SubscriptionManager.OnSubscriptionsChangedListener() { override fun onSubscriptionsChanged() { @@ -58,3 +73,35 @@ fun Context.subscriptionsChangedFlow() = callbackFlow { awaitClose { subscriptionManager.removeOnSubscriptionsChangedListener(listener) } }.conflate().onEach { Log.d(TAG, "subscriptions changed") }.flowOn(Dispatchers.Default) + +/** + * Return a list of subscriptions that are available and visible to the user. + * + * @return list of user selectable subscriptions. + */ +fun Context.getSelectableSubscriptionInfoList(): List { + val subscriptionManager = requireSubscriptionManager() + val availableList = subscriptionManager.getAvailableSubscriptionInfoList() ?: return emptyList() + val visibleList = availableList.filter { subInfo -> + // Opportunistic subscriptions are considered invisible + // to users so they should never be returned. + SubscriptionUtil.isSubscriptionVisible(subscriptionManager, this, subInfo) + } + // Multiple subscriptions in a group should only have one representative. + // It should be the current active primary subscription if any, or any primary subscription. + val groupUuidToSelectedIdMap = visibleList + .groupBy { it.groupUuid } + .mapValues { (_, subInfos) -> + subInfos.filter { it.simSlotIndex != SubscriptionManager.INVALID_SIM_SLOT_INDEX } + .ifEmpty { subInfos } + .minOf { it.subscriptionId } + } + + return visibleList + .filter { subInfo -> + val groupUuid = subInfo.groupUuid ?: return@filter true + groupUuidToSelectedIdMap[groupUuid] == subInfo.subscriptionId + } + .sortedBy { it.subscriptionId } + .also { Log.d(TAG, "getSelectableSubscriptionInfoList: $it") } +} diff --git a/src/com/android/settings/network/telephony/WifiCallingPreferenceController.kt b/src/com/android/settings/network/telephony/WifiCallingPreferenceController.kt index b0ea6a678b2..0ee1d87cd62 100644 --- a/src/com/android/settings/network/telephony/WifiCallingPreferenceController.kt +++ b/src/com/android/settings/network/telephony/WifiCallingPreferenceController.kt @@ -22,10 +22,7 @@ import android.telecom.TelecomManager import android.telephony.SubscriptionManager import android.telephony.TelephonyManager import android.telephony.ims.ImsMmTelManager -import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleOwner -import androidx.lifecycle.lifecycleScope -import androidx.lifecycle.repeatOnLifecycle import androidx.preference.Preference import androidx.preference.PreferenceScreen import com.android.settings.R @@ -33,7 +30,6 @@ import com.android.settings.network.telephony.wificalling.WifiCallingRepository import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.launch import kotlinx.coroutines.withContext /** @@ -81,17 +77,12 @@ open class WifiCallingPreferenceController @JvmOverloads constructor( override fun onViewCreated(viewLifecycleOwner: LifecycleOwner) { wifiCallingRepositoryFactory(mSubId).wifiCallingReadyFlow() - .collectLatestWithLifecycle(viewLifecycleOwner) { - preference.isVisible = it - callingPreferenceCategoryController.updateChildVisible(preferenceKey, it) + .collectLatestWithLifecycle(viewLifecycleOwner) { isReady -> + preference.isVisible = isReady + callingPreferenceCategoryController.updateChildVisible(preferenceKey, isReady) + if (isReady) update() } - viewLifecycleOwner.lifecycleScope.launch { - viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { - update() - } - } - callStateFlowFactory(mSubId).collectLatestWithLifecycle(viewLifecycleOwner) { preference.isEnabled = (it == TelephonyManager.CALL_STATE_IDLE) } diff --git a/src/com/android/settings/network/telephony/scan/NetworkScanRepository.kt b/src/com/android/settings/network/telephony/scan/NetworkScanRepository.kt new file mode 100644 index 00000000000..2067b8c3be5 --- /dev/null +++ b/src/com/android/settings/network/telephony/scan/NetworkScanRepository.kt @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2024 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.network.telephony.scan + +import android.content.Context +import android.telephony.AccessNetworkConstants.AccessNetworkType +import android.telephony.CellInfo +import android.telephony.NetworkScanRequest +import android.telephony.PhoneCapability +import android.telephony.RadioAccessSpecifier +import android.telephony.TelephonyManager +import android.telephony.TelephonyScanManager +import android.util.Log +import androidx.annotation.VisibleForTesting +import androidx.lifecycle.LifecycleOwner +import com.android.settings.network.telephony.CellInfoUtil +import com.android.settings.network.telephony.CellInfoUtil.getNetworkTitle +import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.asExecutor +import kotlinx.coroutines.channels.awaitClose +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.callbackFlow +import kotlinx.coroutines.flow.flowOn + +class NetworkScanRepository(context: Context, subId: Int) { + sealed interface NetworkScanResult + + data class NetworkScanCellInfos(val cellInfos: List) : NetworkScanResult + data object NetworkScanComplete : NetworkScanResult + data class NetworkScanError(val error: Int) : NetworkScanResult + + private val telephonyManager = + context.getSystemService(TelephonyManager::class.java)!!.createForSubscriptionId(subId) + + /** TODO: Move this to UI layer, when UI layer migrated to Kotlin. */ + fun launchNetworkScan(lifecycleOwner: LifecycleOwner, onResult: (NetworkScanResult) -> Unit) { + networkScanFlow().collectLatestWithLifecycle(lifecycleOwner, action = onResult) + } + + data class CellInfoScanKey( + val title: String?, + val className: String, + val isRegistered: Boolean, + ) { + constructor(cellInfo: CellInfo) : this( + title = cellInfo.cellIdentity.getNetworkTitle(), + className = cellInfo.javaClass.name, + isRegistered = cellInfo.isRegistered, + ) + } + + fun networkScanFlow(): Flow = callbackFlow { + val callback = object : TelephonyScanManager.NetworkScanCallback() { + override fun onResults(results: List) { + val cellInfos = results.distinctBy { CellInfoScanKey(it) } + trySend(NetworkScanCellInfos(cellInfos)) + Log.d(TAG, "CellInfoList: ${CellInfoUtil.cellInfoListToString(cellInfos)}") + } + + override fun onComplete() { + trySend(NetworkScanComplete) + close() + Log.d(TAG, "onComplete") + } + + override fun onError(error: Int) { + trySend(NetworkScanError(error)) + close() + Log.d(TAG, "onError: $error") + } + } + + val networkScan = telephonyManager.requestNetworkScan( + createNetworkScan(), + Dispatchers.Default.asExecutor(), + callback, + ) + + awaitClose { networkScan.stopScan() } + }.flowOn(Dispatchers.Default) + + /** Create network scan for allowed network types. */ + private fun createNetworkScan(): NetworkScanRequest { + val allowedNetworkTypes = getAllowedNetworkTypes() + Log.d(TAG, "createNetworkScan: allowedNetworkTypes = $allowedNetworkTypes") + val radioAccessSpecifiers = allowedNetworkTypes + .map { RadioAccessSpecifier(it, null, null) } + .toTypedArray() + return NetworkScanRequest( + NetworkScanRequest.SCAN_TYPE_ONE_SHOT, + radioAccessSpecifiers, + NetworkScanRequest.MIN_SEARCH_PERIODICITY_SEC, // one shot, not used + MAX_SEARCH_TIME_SEC, + true, + INCREMENTAL_RESULTS_PERIODICITY_SEC, + null, + ) + } + + private fun getAllowedNetworkTypes(): List { + val networkTypeBitmap3gpp: Long = + telephonyManager.getAllowedNetworkTypesBitmask() and + TelephonyManager.NETWORK_STANDARDS_FAMILY_BITMASK_3GPP + return buildList { + // If the allowed network types are unknown or if they are of the right class, scan for + // them; otherwise, skip them to save scan time and prevent users from being shown + // networks that they can't connect to. + if (networkTypeBitmap3gpp == 0L + || networkTypeBitmap3gpp and TelephonyManager.NETWORK_CLASS_BITMASK_2G != 0L + ) { + add(AccessNetworkType.GERAN) + } + if (networkTypeBitmap3gpp == 0L + || networkTypeBitmap3gpp and TelephonyManager.NETWORK_CLASS_BITMASK_3G != 0L + ) { + add(AccessNetworkType.UTRAN) + } + if (networkTypeBitmap3gpp == 0L + || networkTypeBitmap3gpp and TelephonyManager.NETWORK_CLASS_BITMASK_4G != 0L + ) { + add(AccessNetworkType.EUTRAN) + } + // If a device supports 5G stand-alone then the code below should be re-enabled; however + // a device supporting only non-standalone mode cannot perform PLMN selection and camp + // on a 5G network, which means that it shouldn't scan for 5G at the expense of battery + // as part of the manual network selection process. + // + if (networkTypeBitmap3gpp == 0L + || (networkTypeBitmap3gpp and TelephonyManager.NETWORK_CLASS_BITMASK_5G != 0L && + hasNrSaCapability()) + ) { + add(AccessNetworkType.NGRAN) + Log.d(TAG, "radioAccessSpecifiers add NGRAN.") + } + } + } + + private fun hasNrSaCapability(): Boolean { + val phoneCapability = telephonyManager.getPhoneCapability() + return PhoneCapability.DEVICE_NR_CAPABILITY_SA in phoneCapability.deviceNrCapabilities + } + + companion object { + private const val TAG = "NetworkScanRepository" + + @VisibleForTesting + val MAX_SEARCH_TIME_SEC = 300 + + @VisibleForTesting + val INCREMENTAL_RESULTS_PERIODICITY_SEC = 3 + } +} diff --git a/src/com/android/settings/password/ChooseLockPassword.java b/src/com/android/settings/password/ChooseLockPassword.java index 631c735e6d0..a6453005ab9 100644 --- a/src/com/android/settings/password/ChooseLockPassword.java +++ b/src/com/android/settings/password/ChooseLockPassword.java @@ -416,6 +416,7 @@ public class ChooseLockPassword extends SettingsActivity { public String getHint(Context context, boolean isAlpha, int type, ProfileType profile) { if (isAlpha) { if (android.os.Flags.allowPrivateProfile() + && android.multiuser.Flags.enablePrivateSpaceFeatures() && profile.equals(ProfileType.Private)) { return context.getString(alphaHintForPrivateProfile); } else if (type == TYPE_FINGERPRINT) { @@ -433,6 +434,7 @@ public class ChooseLockPassword extends SettingsActivity { } } else { if (android.os.Flags.allowPrivateProfile() + && android.multiuser.Flags.enablePrivateSpaceFeatures() && profile.equals(ProfileType.Private)) { return context.getString(numericHintForPrivateProfile); } else if (type == TYPE_FINGERPRINT) { @@ -1147,7 +1149,9 @@ public class ChooseLockPassword extends SettingsActivity { /*flags=*/0).getSystemService(UserManager.class); if (userManager.isManagedProfile()) { return ProfileType.Managed; - } else if (android.os.Flags.allowPrivateProfile() && userManager.isPrivateProfile()) { + } else if (android.os.Flags.allowPrivateProfile() + && android.multiuser.Flags.enablePrivateSpaceFeatures() + && userManager.isPrivateProfile()) { return ProfileType.Private; } else if (userManager.isProfile()) { return ProfileType.Other; diff --git a/src/com/android/settings/password/ChooseLockPattern.java b/src/com/android/settings/password/ChooseLockPattern.java index 8d0aebe6374..c331991a486 100644 --- a/src/com/android/settings/password/ChooseLockPattern.java +++ b/src/com/android/settings/password/ChooseLockPattern.java @@ -478,7 +478,9 @@ public class ChooseLockPattern extends SettingsActivity { .getString(SET_WORK_PROFILE_PATTERN_HEADER, () -> getString( R.string.lockpassword_choose_your_profile_pattern_header)); - } else if (android.os.Flags.allowPrivateProfile() && isPrivateProfile()) { + } else if (android.os.Flags.allowPrivateProfile() + && android.multiuser.Flags.enablePrivateSpaceFeatures() + && isPrivateProfile()) { msg = getString(R.string.private_space_choose_your_pattern_header); } else { msg = getString(R.string.lockpassword_choose_your_pattern_header); diff --git a/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java b/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java index f2ebd1f6b3d..cf805130591 100644 --- a/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java +++ b/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java @@ -300,6 +300,7 @@ public class ConfirmDeviceCredentialActivity extends FragmentActivity { launchedCDC = true; } } else if (android.os.Flags.allowPrivateProfile() + && android.multiuser.Flags.enablePrivateSpaceFeatures() && userProperties != null && userProperties.isAuthAlwaysRequiredToDisableQuietMode() && isInternalActivity()) { @@ -413,7 +414,8 @@ public class ConfirmDeviceCredentialActivity extends FragmentActivity { private boolean doesUserStateEnforceStrongAuth(int userId) { if (android.os.Flags.allowPrivateProfile() - && android.multiuser.Flags.enableBiometricsToUnlockPrivateSpace()) { + && android.multiuser.Flags.enableBiometricsToUnlockPrivateSpace() + && android.multiuser.Flags.enablePrivateSpaceFeatures()) { // Check if CE storage for user is locked since biometrics can't unlock fbe/keystore of // the profile user using verifyTiedProfileChallenge. Biometrics can still be used if // the user is stopped with delayed locking (i.e., with storage unlocked), so the user diff --git a/src/com/android/settings/password/ConfirmDeviceCredentialUtils.java b/src/com/android/settings/password/ConfirmDeviceCredentialUtils.java index 32e7489c6a6..e3182a4521e 100644 --- a/src/com/android/settings/password/ConfirmDeviceCredentialUtils.java +++ b/src/com/android/settings/password/ConfirmDeviceCredentialUtils.java @@ -105,7 +105,8 @@ public class ConfirmDeviceCredentialUtils { private static boolean isBiometricUnlockEnabledForPrivateSpace() { return android.os.Flags.allowPrivateProfile() - && android.multiuser.Flags.enableBiometricsToUnlockPrivateSpace(); + && android.multiuser.Flags.enableBiometricsToUnlockPrivateSpace() + && android.multiuser.Flags.enablePrivateSpaceFeatures(); } /** diff --git a/src/com/android/settings/privatespace/AutoAdvanceSetupFragment.java b/src/com/android/settings/privatespace/AutoAdvanceSetupFragment.java index 1f0f7bb6414..7f0118c5b92 100644 --- a/src/com/android/settings/privatespace/AutoAdvanceSetupFragment.java +++ b/src/com/android/settings/privatespace/AutoAdvanceSetupFragment.java @@ -104,7 +104,8 @@ public class AutoAdvanceSetupFragment extends InstrumentedFragment { @Override public void onCreate(@Nullable Bundle savedInstanceState) { - if (android.os.Flags.allowPrivateProfile()) { + if (android.os.Flags.allowPrivateProfile() + && android.multiuser.Flags.enablePrivateSpaceFeatures()) { super.onCreate(savedInstanceState); } } diff --git a/src/com/android/settings/privatespace/HidePrivateSpaceController.java b/src/com/android/settings/privatespace/HidePrivateSpaceController.java index a53055cefc2..903defa332b 100644 --- a/src/com/android/settings/privatespace/HidePrivateSpaceController.java +++ b/src/com/android/settings/privatespace/HidePrivateSpaceController.java @@ -38,7 +38,10 @@ public class HidePrivateSpaceController extends TogglePreferenceController { @Override @AvailabilityStatus public int getAvailabilityStatus() { - return android.os.Flags.allowPrivateProfile() ? AVAILABLE : UNSUPPORTED_ON_DEVICE; + return android.os.Flags.allowPrivateProfile() + && android.multiuser.Flags.enablePrivateSpaceFeatures() + ? AVAILABLE + : UNSUPPORTED_ON_DEVICE; } @Override diff --git a/src/com/android/settings/privatespace/HidePrivateSpaceSensitiveNotificationsController.java b/src/com/android/settings/privatespace/HidePrivateSpaceSensitiveNotificationsController.java index 1a89d37b8b6..6cb54a1cd89 100644 --- a/src/com/android/settings/privatespace/HidePrivateSpaceSensitiveNotificationsController.java +++ b/src/com/android/settings/privatespace/HidePrivateSpaceSensitiveNotificationsController.java @@ -52,6 +52,7 @@ public class HidePrivateSpaceSensitiveNotificationsController extends TogglePref public int getAvailabilityStatus() { if (!android.os.Flags.allowPrivateProfile() || !android.multiuser.Flags.enablePsSensitiveNotificationsToggle() + || !android.multiuser.Flags.enablePrivateSpaceFeatures() || !mPrivateSpaceMaintainer.doesPrivateSpaceExist()) { return UNSUPPORTED_ON_DEVICE; } diff --git a/src/com/android/settings/privatespace/HidePrivateSpaceSettings.java b/src/com/android/settings/privatespace/HidePrivateSpaceSettings.java index 124978a590c..c41267f3b69 100644 --- a/src/com/android/settings/privatespace/HidePrivateSpaceSettings.java +++ b/src/com/android/settings/privatespace/HidePrivateSpaceSettings.java @@ -27,7 +27,8 @@ public class HidePrivateSpaceSettings extends DashboardFragment{ @Override public void onCreate(Bundle icicle) { - if (android.os.Flags.allowPrivateProfile()) { + if (android.os.Flags.allowPrivateProfile() + && android.multiuser.Flags.enablePrivateSpaceFeatures()) { super.onCreate(icicle); } } diff --git a/src/com/android/settings/privatespace/HidePrivateSpaceSummaryController.java b/src/com/android/settings/privatespace/HidePrivateSpaceSummaryController.java index 42627af93ea..a366b709422 100644 --- a/src/com/android/settings/privatespace/HidePrivateSpaceSummaryController.java +++ b/src/com/android/settings/privatespace/HidePrivateSpaceSummaryController.java @@ -36,7 +36,10 @@ public final class HidePrivateSpaceSummaryController extends BasePreferenceContr @Override public int getAvailabilityStatus() { - return android.os.Flags.allowPrivateProfile() ? AVAILABLE : UNSUPPORTED_ON_DEVICE; + return android.os.Flags.allowPrivateProfile() + && android.multiuser.Flags.enablePrivateSpaceFeatures() + ? AVAILABLE + : UNSUPPORTED_ON_DEVICE; } @Override diff --git a/src/com/android/settings/privatespace/PrivateProfileContextHelperActivity.java b/src/com/android/settings/privatespace/PrivateProfileContextHelperActivity.java index 12a74400952..f2a50dc1e34 100644 --- a/src/com/android/settings/privatespace/PrivateProfileContextHelperActivity.java +++ b/src/com/android/settings/privatespace/PrivateProfileContextHelperActivity.java @@ -59,7 +59,8 @@ public class PrivateProfileContextHelperActivity extends FragmentActivity { @Override protected void onCreate(Bundle savedInstanceState) { - if (!android.os.Flags.allowPrivateProfile()) { + if (!android.os.Flags.allowPrivateProfile() + || !android.multiuser.Flags.enablePrivateSpaceFeatures()) { return; } setTheme(SetupWizardUtils.getTheme(this, getIntent())); diff --git a/src/com/android/settings/privatespace/PrivateSpaceAuthenticationActivity.java b/src/com/android/settings/privatespace/PrivateSpaceAuthenticationActivity.java index 63b1dc95a98..53d6b2272b3 100644 --- a/src/com/android/settings/privatespace/PrivateSpaceAuthenticationActivity.java +++ b/src/com/android/settings/privatespace/PrivateSpaceAuthenticationActivity.java @@ -77,7 +77,8 @@ public class PrivateSpaceAuthenticationActivity extends FragmentActivity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - if (Flags.allowPrivateProfile()) { + if (Flags.allowPrivateProfile() + && android.multiuser.Flags.enablePrivateSpaceFeatures()) { ThemeHelper.trySetDynamicColor(this); mPrivateSpaceMaintainer = new Injector().injectPrivateSpaceMaintainer(getApplicationContext()); diff --git a/src/com/android/settings/privatespace/PrivateSpaceDashboardFragment.java b/src/com/android/settings/privatespace/PrivateSpaceDashboardFragment.java index 726567e08de..32db8b6a7d3 100644 --- a/src/com/android/settings/privatespace/PrivateSpaceDashboardFragment.java +++ b/src/com/android/settings/privatespace/PrivateSpaceDashboardFragment.java @@ -32,7 +32,8 @@ public class PrivateSpaceDashboardFragment extends DashboardFragment { @Override public void onCreate(Bundle icicle) { - if (android.os.Flags.allowPrivateProfile()) { + if (android.os.Flags.allowPrivateProfile() + && android.multiuser.Flags.enablePrivateSpaceFeatures()) { super.onCreate(icicle); if (icicle == null && getIntent().getBooleanExtra(EXTRA_SHOW_PRIVATE_SPACE_UNLOCKED, false)) { diff --git a/src/com/android/settings/privatespace/PrivateSpaceEducation.java b/src/com/android/settings/privatespace/PrivateSpaceEducation.java index 4c99873c20d..cf22895a70b 100644 --- a/src/com/android/settings/privatespace/PrivateSpaceEducation.java +++ b/src/com/android/settings/privatespace/PrivateSpaceEducation.java @@ -43,7 +43,8 @@ public class PrivateSpaceEducation extends InstrumentedFragment { LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - if (!android.os.Flags.allowPrivateProfile()) { + if (!android.os.Flags.allowPrivateProfile() + || !android.multiuser.Flags.enablePrivateSpaceFeatures()) { return null; } GlifLayout rootView = diff --git a/src/com/android/settings/privatespace/PrivateSpaceMaintainer.java b/src/com/android/settings/privatespace/PrivateSpaceMaintainer.java index 2d38ae2007f..3fb9b153b8f 100644 --- a/src/com/android/settings/privatespace/PrivateSpaceMaintainer.java +++ b/src/com/android/settings/privatespace/PrivateSpaceMaintainer.java @@ -78,7 +78,8 @@ public class PrivateSpaceMaintainer { */ @VisibleForTesting public final synchronized boolean createPrivateSpace() { - if (!Flags.allowPrivateProfile()) { + if (!Flags.allowPrivateProfile() + || !android.multiuser.Flags.enablePrivateSpaceFeatures()) { return false; } // Check if Private space already exists @@ -146,7 +147,8 @@ public class PrivateSpaceMaintainer { /** Returns true if the Private space exists. */ public synchronized boolean doesPrivateSpaceExist() { - if (!Flags.allowPrivateProfile()) { + if (!Flags.allowPrivateProfile() + || !android.multiuser.Flags.enablePrivateSpaceFeatures()) { return false; } if (mUserHandle != null) { @@ -322,6 +324,7 @@ public class PrivateSpaceMaintainer { private boolean isPrivateSpaceAutoLockSupported() { return android.os.Flags.allowPrivateProfile() - && android.multiuser.Flags.supportAutolockForPrivateSpace(); + && android.multiuser.Flags.supportAutolockForPrivateSpace() + && android.multiuser.Flags.enablePrivateSpaceFeatures(); } } diff --git a/src/com/android/settings/privatespace/PrivateSpaceSafetySource.java b/src/com/android/settings/privatespace/PrivateSpaceSafetySource.java index 6729830ab67..4e1741a7cda 100644 --- a/src/com/android/settings/privatespace/PrivateSpaceSafetySource.java +++ b/src/com/android/settings/privatespace/PrivateSpaceSafetySource.java @@ -51,7 +51,8 @@ public final class PrivateSpaceSafetySource { return; } - if (!Flags.allowPrivateProfile()) { + if (!Flags.allowPrivateProfile() + || !android.multiuser.Flags.enablePrivateSpaceFeatures()) { // Setting null safetySourceData so that an old entry gets cleared out and this way // provide a response since SC always expects one on rescan. SafetyCenterManagerWrapper.get().setSafetySourceData( diff --git a/src/com/android/settings/privatespace/PrivateSpaceSetLockFragment.java b/src/com/android/settings/privatespace/PrivateSpaceSetLockFragment.java index 4a1e29b2452..399c2c82fbb 100644 --- a/src/com/android/settings/privatespace/PrivateSpaceSetLockFragment.java +++ b/src/com/android/settings/privatespace/PrivateSpaceSetLockFragment.java @@ -51,7 +51,8 @@ public class PrivateSpaceSetLockFragment extends InstrumentedFragment { LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - if (!android.os.Flags.allowPrivateProfile()) { + if (!android.os.Flags.allowPrivateProfile() + || !android.multiuser.Flags.enablePrivateSpaceFeatures()) { return null; } GlifLayout rootView = diff --git a/src/com/android/settings/privatespace/PrivateSpaceSetupActivity.java b/src/com/android/settings/privatespace/PrivateSpaceSetupActivity.java index 78c96dcc5f3..ec7132adf0e 100644 --- a/src/com/android/settings/privatespace/PrivateSpaceSetupActivity.java +++ b/src/com/android/settings/privatespace/PrivateSpaceSetupActivity.java @@ -42,7 +42,8 @@ public class PrivateSpaceSetupActivity extends FragmentActivity { @Override protected void onCreate(Bundle savedInstanceState) { - if (!android.os.Flags.allowPrivateProfile()) { + if (!android.os.Flags.allowPrivateProfile() + || !android.multiuser.Flags.enablePrivateSpaceFeatures()) { return; } setTheme(SetupWizardUtils.getTheme(this, getIntent())); diff --git a/src/com/android/settings/privatespace/SetupSuccessFragment.java b/src/com/android/settings/privatespace/SetupSuccessFragment.java index 13de1fc94fc..cf63b22fead 100644 --- a/src/com/android/settings/privatespace/SetupSuccessFragment.java +++ b/src/com/android/settings/privatespace/SetupSuccessFragment.java @@ -47,7 +47,8 @@ public class SetupSuccessFragment extends InstrumentedFragment { LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - if (!android.os.Flags.allowPrivateProfile()) { + if (!android.os.Flags.allowPrivateProfile() + || !android.multiuser.Flags.enablePrivateSpaceFeatures()) { return null; } GlifLayout rootView = diff --git a/src/com/android/settings/privatespace/autolock/AutoLockPreferenceController.java b/src/com/android/settings/privatespace/autolock/AutoLockPreferenceController.java index a7a12a4950c..3416e143d65 100644 --- a/src/com/android/settings/privatespace/autolock/AutoLockPreferenceController.java +++ b/src/com/android/settings/privatespace/autolock/AutoLockPreferenceController.java @@ -40,7 +40,8 @@ public class AutoLockPreferenceController extends BasePreferenceController { @Override public int getAvailabilityStatus() { return android.os.Flags.allowPrivateProfile() - && android.multiuser.Flags.supportAutolockForPrivateSpace() + && android.multiuser.Flags.supportAutolockForPrivateSpace() + && android.multiuser.Flags.enablePrivateSpaceFeatures() ? AVAILABLE : UNSUPPORTED_ON_DEVICE; } diff --git a/src/com/android/settings/privatespace/autolock/AutoLockSettingsFragment.java b/src/com/android/settings/privatespace/autolock/AutoLockSettingsFragment.java index 4380c534a04..cb332d1e515 100644 --- a/src/com/android/settings/privatespace/autolock/AutoLockSettingsFragment.java +++ b/src/com/android/settings/privatespace/autolock/AutoLockSettingsFragment.java @@ -47,7 +47,8 @@ public class AutoLockSettingsFragment extends RadioButtonPickerFragment { @Override public void onCreate(@NonNull Bundle icicle) { if (android.os.Flags.allowPrivateProfile() - && android.multiuser.Flags.supportAutolockForPrivateSpace()) { + && android.multiuser.Flags.supportAutolockForPrivateSpace() + && android.multiuser.Flags.enablePrivateSpaceFeatures()) { super.onCreate(icicle); } } diff --git a/src/com/android/settings/privatespace/delete/DeletePrivateSpaceController.java b/src/com/android/settings/privatespace/delete/DeletePrivateSpaceController.java index af4535ec43a..a2fc6f81d67 100644 --- a/src/com/android/settings/privatespace/delete/DeletePrivateSpaceController.java +++ b/src/com/android/settings/privatespace/delete/DeletePrivateSpaceController.java @@ -34,7 +34,10 @@ public class DeletePrivateSpaceController extends BasePreferenceController { @Override public int getAvailabilityStatus() { - return android.os.Flags.allowPrivateProfile() ? AVAILABLE : UNSUPPORTED_ON_DEVICE; + return android.os.Flags.allowPrivateProfile() + && android.multiuser.Flags.enablePrivateSpaceFeatures() + ? AVAILABLE + : UNSUPPORTED_ON_DEVICE; } @Override diff --git a/src/com/android/settings/privatespace/delete/PrivateSpaceDeleteActivity.java b/src/com/android/settings/privatespace/delete/PrivateSpaceDeleteActivity.java index a4109b868bc..b483aa3a460 100644 --- a/src/com/android/settings/privatespace/delete/PrivateSpaceDeleteActivity.java +++ b/src/com/android/settings/privatespace/delete/PrivateSpaceDeleteActivity.java @@ -35,7 +35,8 @@ public class PrivateSpaceDeleteActivity extends InstrumentedActivity { @Override protected void onCreate(Bundle savedInstanceState) { - if (!android.os.Flags.allowPrivateProfile()) { + if (!android.os.Flags.allowPrivateProfile() + || !android.multiuser.Flags.enablePrivateSpaceFeatures()) { return; } setTheme(SetupWizardUtils.getTheme(this, getIntent())); diff --git a/src/com/android/settings/privatespace/delete/PrivateSpaceDeleteFragment.java b/src/com/android/settings/privatespace/delete/PrivateSpaceDeleteFragment.java index 7dd3a5b0102..bcc220f1813 100644 --- a/src/com/android/settings/privatespace/delete/PrivateSpaceDeleteFragment.java +++ b/src/com/android/settings/privatespace/delete/PrivateSpaceDeleteFragment.java @@ -56,7 +56,8 @@ public class PrivateSpaceDeleteFragment extends InstrumentedFragment { @Override public void onCreate(@Nullable Bundle icicle) { - if (android.os.Flags.allowPrivateProfile()) { + if (android.os.Flags.allowPrivateProfile() + && android.multiuser.Flags.enablePrivateSpaceFeatures()) { super.onCreate(icicle); } } diff --git a/src/com/android/settings/privatespace/delete/PrivateSpaceDeletionProgressFragment.java b/src/com/android/settings/privatespace/delete/PrivateSpaceDeletionProgressFragment.java index 3a166413565..33f0a3ee362 100644 --- a/src/com/android/settings/privatespace/delete/PrivateSpaceDeletionProgressFragment.java +++ b/src/com/android/settings/privatespace/delete/PrivateSpaceDeletionProgressFragment.java @@ -62,7 +62,8 @@ public class PrivateSpaceDeletionProgressFragment extends InstrumentedFragment { @Override public void onCreate(@Nullable Bundle savedInstanceState) { - if (android.os.Flags.allowPrivateProfile()) { + if (android.os.Flags.allowPrivateProfile() + && android.multiuser.Flags.enablePrivateSpaceFeatures()) { super.onCreate(savedInstanceState); } } diff --git a/src/com/android/settings/privatespace/onelock/FaceFingerprintUnlockController.java b/src/com/android/settings/privatespace/onelock/FaceFingerprintUnlockController.java index 2e3f2840b70..04f489401ed 100644 --- a/src/com/android/settings/privatespace/onelock/FaceFingerprintUnlockController.java +++ b/src/com/android/settings/privatespace/onelock/FaceFingerprintUnlockController.java @@ -42,6 +42,7 @@ public class FaceFingerprintUnlockController extends CombinedBiometricStatusPref protected boolean isUserSupported() { return android.os.Flags.allowPrivateProfile() && android.multiuser.Flags.enableBiometricsToUnlockPrivateSpace() + && android.multiuser.Flags.enablePrivateSpaceFeatures() && mProfileUserId != UserHandle.USER_NULL; } diff --git a/src/com/android/settings/privatespace/onelock/PrivateSpaceBiometricSettings.java b/src/com/android/settings/privatespace/onelock/PrivateSpaceBiometricSettings.java index dc00885cf87..827f0b72b60 100644 --- a/src/com/android/settings/privatespace/onelock/PrivateSpaceBiometricSettings.java +++ b/src/com/android/settings/privatespace/onelock/PrivateSpaceBiometricSettings.java @@ -34,7 +34,8 @@ public class PrivateSpaceBiometricSettings extends BiometricsSettingsBase { @Override public void onAttach(Context context) { if (android.os.Flags.allowPrivateProfile() - && android.multiuser.Flags.enableBiometricsToUnlockPrivateSpace()) { + && android.multiuser.Flags.enableBiometricsToUnlockPrivateSpace() + && android.multiuser.Flags.enablePrivateSpaceFeatures()) { super.onAttach(context); UserHandle privateProfileHandle = PrivateSpaceMaintainer.getInstance(context).getPrivateProfileHandle(); diff --git a/src/com/android/settings/privatespace/onelock/PrivateSpaceFacePreferenceController.java b/src/com/android/settings/privatespace/onelock/PrivateSpaceFacePreferenceController.java index b841d9aded5..583a093dbc2 100644 --- a/src/com/android/settings/privatespace/onelock/PrivateSpaceFacePreferenceController.java +++ b/src/com/android/settings/privatespace/onelock/PrivateSpaceFacePreferenceController.java @@ -45,6 +45,7 @@ public class PrivateSpaceFacePreferenceController extends BiometricFaceStatusPre protected boolean isUserSupported() { return android.os.Flags.allowPrivateProfile() && android.multiuser.Flags.enableBiometricsToUnlockPrivateSpace() + && android.multiuser.Flags.enablePrivateSpaceFeatures() && getUserId() != UserHandle.USER_NULL; } @@ -63,7 +64,8 @@ public class PrivateSpaceFacePreferenceController extends BiometricFaceStatusPre @Override public int getAvailabilityStatus() { return android.os.Flags.allowPrivateProfile() - && android.multiuser.Flags.enableBiometricsToUnlockPrivateSpace() + && android.multiuser.Flags.enableBiometricsToUnlockPrivateSpace() + && android.multiuser.Flags.enablePrivateSpaceFeatures() ? AVAILABLE : UNSUPPORTED_ON_DEVICE; } diff --git a/src/com/android/settings/privatespace/onelock/PrivateSpaceFingerprintPreferenceController.java b/src/com/android/settings/privatespace/onelock/PrivateSpaceFingerprintPreferenceController.java index d48490460b5..f88c9facccc 100644 --- a/src/com/android/settings/privatespace/onelock/PrivateSpaceFingerprintPreferenceController.java +++ b/src/com/android/settings/privatespace/onelock/PrivateSpaceFingerprintPreferenceController.java @@ -47,6 +47,7 @@ public class PrivateSpaceFingerprintPreferenceController protected boolean isUserSupported() { return android.os.Flags.allowPrivateProfile() && android.multiuser.Flags.enableBiometricsToUnlockPrivateSpace() + && android.multiuser.Flags.enablePrivateSpaceFeatures() && getUserId() != UserHandle.USER_NULL; } @@ -65,7 +66,8 @@ public class PrivateSpaceFingerprintPreferenceController @Override public int getAvailabilityStatus() { return android.os.Flags.allowPrivateProfile() - && android.multiuser.Flags.enableBiometricsToUnlockPrivateSpace() + && android.multiuser.Flags.enableBiometricsToUnlockPrivateSpace() + && android.multiuser.Flags.enablePrivateSpaceFeatures() ? AVAILABLE : UNSUPPORTED_ON_DEVICE; } diff --git a/src/com/android/settings/privatespace/onelock/PrivateSpaceLockController.java b/src/com/android/settings/privatespace/onelock/PrivateSpaceLockController.java index efbe9f9200d..e0f376e1007 100644 --- a/src/com/android/settings/privatespace/onelock/PrivateSpaceLockController.java +++ b/src/com/android/settings/privatespace/onelock/PrivateSpaceLockController.java @@ -74,7 +74,8 @@ public class PrivateSpaceLockController extends AbstractPreferenceController { @Override public boolean isAvailable() { - return android.os.Flags.allowPrivateProfile(); + return android.os.Flags.allowPrivateProfile() + && android.multiuser.Flags.enablePrivateSpaceFeatures(); } @Override diff --git a/src/com/android/settings/privatespace/onelock/UseOneLockController.java b/src/com/android/settings/privatespace/onelock/UseOneLockController.java index 31634b9ea00..1af36b333b6 100644 --- a/src/com/android/settings/privatespace/onelock/UseOneLockController.java +++ b/src/com/android/settings/privatespace/onelock/UseOneLockController.java @@ -45,7 +45,10 @@ public class UseOneLockController extends BasePreferenceController { } @Override public int getAvailabilityStatus() { - return android.os.Flags.allowPrivateProfile() ? AVAILABLE : UNSUPPORTED_ON_DEVICE; + return android.os.Flags.allowPrivateProfile() + && android.multiuser.Flags.enablePrivateSpaceFeatures() + ? AVAILABLE + : UNSUPPORTED_ON_DEVICE; } @Override diff --git a/src/com/android/settings/privatespace/onelock/UseOneLockControllerSwitch.java b/src/com/android/settings/privatespace/onelock/UseOneLockControllerSwitch.java index fd7d02b6c7a..680f5c7de0e 100644 --- a/src/com/android/settings/privatespace/onelock/UseOneLockControllerSwitch.java +++ b/src/com/android/settings/privatespace/onelock/UseOneLockControllerSwitch.java @@ -95,7 +95,8 @@ public class UseOneLockControllerSwitch extends AbstractPreferenceController @Override public boolean isAvailable() { - return android.os.Flags.allowPrivateProfile(); + return android.os.Flags.allowPrivateProfile() + && android.multiuser.Flags.enablePrivateSpaceFeatures(); } @Override diff --git a/src/com/android/settings/privatespace/onelock/UseOneLockSettingsFragment.java b/src/com/android/settings/privatespace/onelock/UseOneLockSettingsFragment.java index 413e02a16f8..ce017e31152 100644 --- a/src/com/android/settings/privatespace/onelock/UseOneLockSettingsFragment.java +++ b/src/com/android/settings/privatespace/onelock/UseOneLockSettingsFragment.java @@ -39,7 +39,8 @@ public class UseOneLockSettingsFragment extends DashboardFragment { @Override public void onCreate(Bundle icicle) { - if (android.os.Flags.allowPrivateProfile()) { + if (android.os.Flags.allowPrivateProfile() + && android.multiuser.Flags.enablePrivateSpaceFeatures()) { super.onCreate(icicle); } } diff --git a/src/com/android/settings/safetycenter/BiometricsSafetySource.java b/src/com/android/settings/safetycenter/BiometricsSafetySource.java index 8e1c78644d9..c93ced1a50d 100644 --- a/src/com/android/settings/safetycenter/BiometricsSafetySource.java +++ b/src/com/android/settings/safetycenter/BiometricsSafetySource.java @@ -62,7 +62,9 @@ public final class BiometricsSafetySource { } final Context profileParentContext = context.createContextAsUser(profileParentUserHandle, 0); - if (android.os.Flags.allowPrivateProfile() && userManager.isPrivateProfile()) { + if (android.os.Flags.allowPrivateProfile() + && android.multiuser.Flags.enablePrivateSpaceFeatures() + && userManager.isPrivateProfile()) { // SC always expects a response from the source if the broadcast has been sent for this // source, therefore, we need to send a null SafetySourceData. SafetyCenterManagerWrapper.get().setSafetySourceData( diff --git a/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProvider.kt b/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProvider.kt index 15cd1bab5f6..3241d713cf4 100644 --- a/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProvider.kt +++ b/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProvider.kt @@ -62,6 +62,7 @@ import com.android.settingslib.spaprivileged.template.app.AppListItem import com.android.settingslib.spaprivileged.template.app.AppListItemModel import com.android.settingslib.spaprivileged.template.app.AppListPage import com.google.common.annotations.VisibleForTesting +import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine @@ -130,8 +131,10 @@ data class UserAspectRatioAppListItemModel( val canDisplay: Boolean, ) : AppRecord -class UserAspectRatioAppListModel(private val context: Context) - : AppListModel { +class UserAspectRatioAppListModel( + private val context: Context, + private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO +) : AppListModel { private val packageManager = context.packageManager private val userAspectRatioManager = UserAspectRatioManager(context) @@ -203,7 +206,7 @@ class UserAspectRatioAppListModel(private val context: Context) flow { emit(userAspectRatioManager.getUserMinAspectRatioEntry(record.userOverride, record.app.packageName, record.app.userId)) - }.flowOn(Dispatchers.IO) + }.flowOn(ioDispatcher) }.collectAsStateWithLifecycle(initialValue = stringResource(R.string.summary_placeholder)) return { summary } } diff --git a/tests/robotests/src/com/android/settings/accessibility/KeyboardVibrationTogglePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/KeyboardVibrationTogglePreferenceControllerTest.java index cf12e341337..2d5905e8de8 100644 --- a/tests/robotests/src/com/android/settings/accessibility/KeyboardVibrationTogglePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/KeyboardVibrationTogglePreferenceControllerTest.java @@ -84,6 +84,9 @@ public class KeyboardVibrationTogglePreferenceControllerTest { public void getAvailabilityStatus_featureSupported_available() { mSetFlagsRule.enableFlags(Flags.FLAG_KEYBOARD_CATEGORY_ENABLED); when(mResources.getBoolean(R.bool.config_keyboard_vibration_supported)).thenReturn(true); + when(mResources.getFloat( + com.android.internal.R.dimen.config_keyboardHapticFeedbackFixedAmplitude)) + .thenReturn(0.8f); assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE); } diff --git a/tests/robotests/src/com/android/settings/applications/appcompat/UserAspectRatioDetailsTest.java b/tests/robotests/src/com/android/settings/applications/appcompat/UserAspectRatioDetailsTest.java index f3b105bc3d6..ce03a6def34 100644 --- a/tests/robotests/src/com/android/settings/applications/appcompat/UserAspectRatioDetailsTest.java +++ b/tests/robotests/src/com/android/settings/applications/appcompat/UserAspectRatioDetailsTest.java @@ -16,16 +16,19 @@ package com.android.settings.applications.appcompat; +import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_3_2; import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_APP_DEFAULT; import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_FULLSCREEN; import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_UNSET; import static com.android.settings.applications.AppInfoBase.ARG_PACKAGE_NAME; +import static com.android.settings.applications.appcompat.UserAspectRatioDetails.KEY_HEADER_BUTTONS; import static com.android.settings.applications.appcompat.UserAspectRatioDetails.KEY_PREF_3_2; import static com.android.settings.applications.appcompat.UserAspectRatioDetails.KEY_PREF_DEFAULT; import static com.android.settings.applications.appcompat.UserAspectRatioDetails.KEY_PREF_FULLSCREEN; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; @@ -98,6 +101,31 @@ public class UserAspectRatioDetailsTest { mMetricsFeatureProvider = featureFactory.metricsFeatureProvider; } + @Test + public void testOrderOfOptionsFollowsConfig() { + doReturn(true).when(mUserAspectRatioManager) + .hasAspectRatioOption(anyInt(), anyString()); + doReturn(0).when(mUserAspectRatioManager) + .getUserMinAspectRatioOrder(USER_MIN_ASPECT_RATIO_3_2); + doReturn(1).when(mUserAspectRatioManager) + .getUserMinAspectRatioOrder(USER_MIN_ASPECT_RATIO_FULLSCREEN); + doReturn(2).when(mUserAspectRatioManager) + .getUserMinAspectRatioOrder(USER_MIN_ASPECT_RATIO_UNSET); + rule.getScenario().onActivity(a -> doReturn(a).when(mFragment).getActivity()); + final Bundle args = new Bundle(); + args.putString(ARG_PACKAGE_NAME, anyString()); + mFragment.setArguments(args); + mFragment.onCreate(Bundle.EMPTY); + + final int topOfList = mFragment.findPreference(KEY_HEADER_BUTTONS).getOrder(); + + assertTrue(topOfList < mFragment.findPreference(KEY_PREF_3_2).getOrder()); + assertTrue(mFragment.findPreference(KEY_PREF_3_2).getOrder() + < mFragment.findPreference(KEY_PREF_FULLSCREEN).getOrder()); + assertTrue(mFragment.findPreference(KEY_PREF_FULLSCREEN).getOrder() + < mFragment.findPreference(KEY_PREF_DEFAULT).getOrder()); + } + @Test public void onRadioButtonClicked_prefChange_shouldStopActivity() throws RemoteException { doReturn(USER_MIN_ASPECT_RATIO_UNSET).when(mFragment) diff --git a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroductionTest.java b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroductionTest.java index 1aedce53980..6df8b8ef4b9 100644 --- a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroductionTest.java +++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroductionTest.java @@ -252,6 +252,24 @@ public class FingerprintEnrollIntroductionTest { assertThat(result).isEqualTo(R.string.fingerprint_intro_error_max); } + @Test + public void intro_CheckNullPropsReturnsErrorString() { + setupFingerprintEnrollIntroWith(newTokenOnlyIntent()); + when(mFingerprintManager.getSensorPropertiesInternal()).thenReturn(null); + final int result = mFingerprintEnrollIntroduction.checkMaxEnrolled(); + + assertThat(result).isEqualTo(R.string.fingerprint_intro_error_unknown); + } + + @Test + public void intro_CheckEmptyPropsReturnsErrorString() { + setupFingerprintEnrollIntroWith(newTokenOnlyIntent()); + when(mFingerprintManager.getSensorPropertiesInternal()).thenReturn(List.of()); + final int result = mFingerprintEnrollIntroduction.checkMaxEnrolled(); + + assertThat(result).isEqualTo(R.string.fingerprint_intro_error_unknown); + } + @Test public void intro_CheckGenerateChallenge() { setupFingerprintEnrollIntroWith(newGkPwHandleAndFromSettingsIntent()); 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 b6af0f908cc..46e4ea5d117 100644 --- a/tests/robotests/src/com/android/settings/dashboard/profileselector/ProfileSelectFragmentTest.java +++ b/tests/robotests/src/com/android/settings/dashboard/profileselector/ProfileSelectFragmentTest.java @@ -174,7 +174,8 @@ public class ProfileSelectFragmentTest { @Test public void getTabId_setPrivateId_getCorrectTab() { - mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE); + mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); final Bundle bundle = new Bundle(); bundle.putInt(EXTRA_USER_ID, 11); mUserManager.setPrivateProfile(11, "private", 0); @@ -204,7 +205,8 @@ public class ProfileSelectFragmentTest { @Test public void testGetFragments_whenOnlyPersonal_returnsOneFragment() { - mSetFlagsRule.disableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE); + mSetFlagsRule.disableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); mUserManager.addProfile( new UserInfo(0, PRIMARY_USER_NAME, null, 0, USER_TYPE_FULL_SYSTEM)); Fragment[] fragments = ProfileSelectFragment.getFragments( @@ -239,7 +241,8 @@ public class ProfileSelectFragmentTest { @Test public void testGetFragments_whenPrivateEnabled_returnsTwoFragments() { - mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE); + mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); mUserManager.addProfile( new UserInfo(0, PRIMARY_USER_NAME, null, 0, USER_TYPE_FULL_SYSTEM)); mUserManager.addProfile( @@ -261,7 +264,8 @@ public class ProfileSelectFragmentTest { @Test public void testGetFragments_whenManagedProfile_returnsTwoFragments() { - mSetFlagsRule.disableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE); + mSetFlagsRule.disableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); mUserManager.addProfile( new UserInfo(0, PRIMARY_USER_NAME, null, 0, USER_TYPE_FULL_SYSTEM)); mUserManager.addProfile( @@ -283,7 +287,8 @@ public class ProfileSelectFragmentTest { @Test public void testGetFragments_whenAllProfiles_returnsThreeFragments() { - mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE); + mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); mUserManager.addProfile( new UserInfo(0, PRIMARY_USER_NAME, null, 0, USER_TYPE_FULL_SYSTEM)); mUserManager.addProfile( @@ -307,7 +312,8 @@ public class ProfileSelectFragmentTest { @Test public void testGetFragments_whenAvailableBundle_returnsFragmentsWithCorrectBundles() { - mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE); + mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); mUserManager.addProfile( new UserInfo(0, PRIMARY_USER_NAME, null, 0, USER_TYPE_FULL_SYSTEM)); mUserManager.addProfile( diff --git a/tests/robotests/src/com/android/settings/development/quarantine/QuarantinedAppsScreenControllerTest.java b/tests/robotests/src/com/android/settings/development/quarantine/QuarantinedAppsScreenControllerTest.java deleted file mode 100644 index a93e5291192..00000000000 --- a/tests/robotests/src/com/android/settings/development/quarantine/QuarantinedAppsScreenControllerTest.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (C) 2023 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.development.quarantine; - -import static org.mockito.AdditionalMatchers.aryEq; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.isNull; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; - -import android.content.Context; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; -import android.content.pm.SuspendDialogInfo; -import android.os.UserHandle; - -import androidx.test.core.app.ApplicationProvider; - -import com.android.settingslib.applications.ApplicationsState.AppEntry; - -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 QuarantinedAppsScreenControllerTest { - private static final String PREF_KEY = "quarantined_apps_screen"; - private static final String TEST_PACKAGE = "com.example.test.pkg"; - private static final int TEST_APP_ID = 1234; - private static final int TEST_USER_ID = 10; - - private Context mContext; - private QuarantinedAppsScreenController mController; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - mContext = spy(ApplicationProvider.getApplicationContext()); - mController = new QuarantinedAppsScreenController(mContext, PREF_KEY); - } - - @Test - public void testOnPreferenceChange() { - final Context userContext = mock(Context.class); - doReturn(userContext).when(mContext).createContextAsUser( - eq(UserHandle.of(TEST_USER_ID)), anyInt()); - final PackageManager packageManager = mock(PackageManager.class); - doReturn(packageManager).when(userContext).getPackageManager(); - - final AppEntry entry = createAppEntry(TEST_PACKAGE, TEST_APP_ID, TEST_USER_ID); - final QuarantinedAppPreference preference = new QuarantinedAppPreference(mContext, entry); - - mController.onPreferenceChange(preference, true); - verify(packageManager).setPackagesSuspended(aryEq(new String[] {TEST_PACKAGE}), eq(true), - isNull(), isNull(), any(SuspendDialogInfo.class), - eq(PackageManager.FLAG_SUSPEND_QUARANTINED)); - - mController.onPreferenceChange(preference, false); - verify(packageManager).setPackagesSuspended(aryEq(new String[] {TEST_PACKAGE}), eq(false), - isNull(), isNull(), isNull(), - eq(PackageManager.FLAG_SUSPEND_QUARANTINED)); - } - - private AppEntry createAppEntry(String packageName, int appId, int userId) { - final AppEntry entry = mock(AppEntry.class); - entry.info = createApplicationInfo(packageName, appId, userId); - entry.extraInfo = false; - return entry; - } - - private ApplicationInfo createApplicationInfo(String packageName, int appId, int userId) { - final ApplicationInfo info = new ApplicationInfo(); - info.packageName = packageName; - info.uid = UserHandle.getUid(userId, appId); - return info; - } -} diff --git a/tests/spa_unit/src/com/android/settings/network/telephony/MobileNetworkSwitchControllerTest.kt b/tests/spa_unit/src/com/android/settings/network/telephony/MobileNetworkSwitchControllerTest.kt new file mode 100644 index 00000000000..ca370829b6f --- /dev/null +++ b/tests/spa_unit/src/com/android/settings/network/telephony/MobileNetworkSwitchControllerTest.kt @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2024 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.network.telephony + +import android.content.Context +import android.telephony.SubscriptionInfo +import android.telephony.SubscriptionManager +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.hasText +import androidx.compose.ui.test.isOff +import androidx.compose.ui.test.isOn +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.test.onNodeWithText +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.android.settings.R +import com.android.settingslib.spa.testutils.waitUntilExists +import kotlinx.coroutines.flow.flowOf +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.kotlin.any +import org.mockito.kotlin.doNothing +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import org.mockito.kotlin.spy +import org.mockito.kotlin.stub +import org.mockito.kotlin.whenever + +@RunWith(AndroidJUnit4::class) +class MobileNetworkSwitchControllerTest { + @get:Rule + val composeTestRule = createComposeRule() + + private val mockSubscriptionManager = mock { + on { isSubscriptionEnabled(SUB_ID) } doReturn true + } + + private val context: Context = spy(ApplicationProvider.getApplicationContext()) { + on { subscriptionManager } doReturn mockSubscriptionManager + doNothing().whenever(mock).startActivity(any()) + } + + private val mockSubscriptionRepository = mock { + on { getSelectableSubscriptionInfoList() } doReturn listOf(SubInfo) + on { isSubscriptionEnabledFlow(SUB_ID) } doReturn flowOf(false) + } + + private val controller = MobileNetworkSwitchController( + context = context, + preferenceKey = TEST_KEY, + subscriptionRepository = mockSubscriptionRepository, + ).apply { init(SUB_ID) } + + @Test + fun isVisible_pSimAndCanDisablePhysicalSubscription_returnTrue() { + val pSimSubInfo = SubscriptionInfo.Builder().apply { + setId(SUB_ID) + setEmbedded(false) + }.build() + mockSubscriptionManager.stub { + on { canDisablePhysicalSubscription() } doReturn true + } + mockSubscriptionRepository.stub { + on { getSelectableSubscriptionInfoList() } doReturn listOf(pSimSubInfo) + } + + setContent() + + composeTestRule.onNodeWithText(context.getString(R.string.mobile_network_use_sim_on)) + .assertIsDisplayed() + } + + @Test + fun isVisible_pSimAndCannotDisablePhysicalSubscription_returnFalse() { + val pSimSubInfo = SubscriptionInfo.Builder().apply { + setId(SUB_ID) + setEmbedded(false) + }.build() + mockSubscriptionManager.stub { + on { canDisablePhysicalSubscription() } doReturn false + } + mockSubscriptionRepository.stub { + on { getSelectableSubscriptionInfoList() } doReturn listOf(pSimSubInfo) + } + + setContent() + + composeTestRule.onNodeWithText(context.getString(R.string.mobile_network_use_sim_on)) + .assertDoesNotExist() + } + + @Test + fun isVisible_eSim_returnTrue() { + val eSimSubInfo = SubscriptionInfo.Builder().apply { + setId(SUB_ID) + setEmbedded(true) + }.build() + mockSubscriptionRepository.stub { + on { getSelectableSubscriptionInfoList() } doReturn listOf(eSimSubInfo) + } + + setContent() + + composeTestRule.onNodeWithText(context.getString(R.string.mobile_network_use_sim_on)) + .assertIsDisplayed() + } + + @Test + fun isChecked_subscriptionEnabled_switchIsOn() { + mockSubscriptionRepository.stub { + on { isSubscriptionEnabledFlow(SUB_ID) } doReturn flowOf(true) + } + + setContent() + + composeTestRule.waitUntilExists( + hasText(context.getString(R.string.mobile_network_use_sim_on)) and isOn() + ) + } + + @Test + fun isChecked_subscriptionNotEnabled_switchIsOff() { + mockSubscriptionRepository.stub { + on { isSubscriptionEnabledFlow(SUB_ID) } doReturn flowOf(false) + } + + setContent() + + composeTestRule.waitUntilExists( + hasText(context.getString(R.string.mobile_network_use_sim_on)) and isOff() + ) + } + + private fun setContent() { + composeTestRule.setContent { + CompositionLocalProvider(LocalContext provides context) { + controller.Content() + } + } + } + + private companion object { + const val TEST_KEY = "test_key" + const val SUB_ID = 123 + + val SubInfo: SubscriptionInfo = SubscriptionInfo.Builder().apply { + setId(SUB_ID) + setEmbedded(true) + }.build() + } +} diff --git a/tests/spa_unit/src/com/android/settings/network/telephony/SubscriptionRepositoryTest.kt b/tests/spa_unit/src/com/android/settings/network/telephony/SubscriptionRepositoryTest.kt index a59bf932508..80b317552bb 100644 --- a/tests/spa_unit/src/com/android/settings/network/telephony/SubscriptionRepositoryTest.kt +++ b/tests/spa_unit/src/com/android/settings/network/telephony/SubscriptionRepositoryTest.kt @@ -17,12 +17,14 @@ package com.android.settings.network.telephony import android.content.Context +import android.telephony.SubscriptionInfo import android.telephony.SubscriptionManager import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 import com.android.settingslib.spa.testutils.firstWithTimeoutOrNull import com.android.settingslib.spa.testutils.toListWithTimeout import com.google.common.truth.Truth.assertThat +import java.util.UUID import kotlinx.coroutines.async import kotlinx.coroutines.delay import kotlinx.coroutines.runBlocking @@ -47,16 +49,16 @@ class SubscriptionRepositoryTest { } private val context: Context = spy(ApplicationProvider.getApplicationContext()) { - on { getSystemService(SubscriptionManager::class.java) } doReturn mockSubscriptionManager + on { subscriptionManager } doReturn mockSubscriptionManager } @Test fun isSubscriptionEnabledFlow() = runBlocking { mockSubscriptionManager.stub { - on { isSubscriptionEnabled(SUB_ID) } doReturn true + on { isSubscriptionEnabled(SUB_ID_1) } doReturn true } - val isEnabled = context.isSubscriptionEnabledFlow(SUB_ID).firstWithTimeoutOrNull() + val isEnabled = context.isSubscriptionEnabledFlow(SUB_ID_1).firstWithTimeoutOrNull() assertThat(isEnabled).isTrue() } @@ -80,7 +82,69 @@ class SubscriptionRepositoryTest { assertThat(listDeferred.await()).hasSize(2) } + @Test + fun getSelectableSubscriptionInfoList_sortedBySubId() { + mockSubscriptionManager.stub { + on { getAvailableSubscriptionInfoList() } doReturn listOf( + SubscriptionInfo.Builder().apply { + setId(SUB_ID_2) + }.build(), + SubscriptionInfo.Builder().apply { + setId(SUB_ID_1) + }.build(), + ) + } + + val subInfos = context.getSelectableSubscriptionInfoList() + + assertThat(subInfos.map { it.subscriptionId }).containsExactly(SUB_ID_1, SUB_ID_2).inOrder() + } + + @Test + fun getSelectableSubscriptionInfoList_sameGroupAndOneHasSlot_returnTheOneWithSimSlotIndex() { + mockSubscriptionManager.stub { + on { getAvailableSubscriptionInfoList() } doReturn listOf( + SubscriptionInfo.Builder().apply { + setId(SUB_ID_1) + setGroupUuid(GROUP_UUID) + }.build(), + SubscriptionInfo.Builder().apply { + setId(SUB_ID_2) + setGroupUuid(GROUP_UUID) + setSimSlotIndex(SIM_SLOT_INDEX) + }.build(), + ) + } + + val subInfos = context.getSelectableSubscriptionInfoList() + + assertThat(subInfos.map { it.subscriptionId }).containsExactly(SUB_ID_2) + } + + @Test + fun getSelectableSubscriptionInfoList_sameGroupAndNonHasSlot_returnTheOneWithMinimumSubId() { + mockSubscriptionManager.stub { + on { getAvailableSubscriptionInfoList() } doReturn listOf( + SubscriptionInfo.Builder().apply { + setId(SUB_ID_2) + setGroupUuid(GROUP_UUID) + }.build(), + SubscriptionInfo.Builder().apply { + setId(SUB_ID_1) + setGroupUuid(GROUP_UUID) + }.build(), + ) + } + + val subInfos = context.getSelectableSubscriptionInfoList() + + assertThat(subInfos.map { it.subscriptionId }).containsExactly(SUB_ID_1) + } + private companion object { - const val SUB_ID = 1 + const val SUB_ID_1 = 1 + const val SUB_ID_2 = 2 + val GROUP_UUID = UUID.randomUUID().toString() + const val SIM_SLOT_INDEX = 1 } } diff --git a/tests/spa_unit/src/com/android/settings/network/telephony/scan/NetworkScanRepositoryTest.kt b/tests/spa_unit/src/com/android/settings/network/telephony/scan/NetworkScanRepositoryTest.kt new file mode 100644 index 00000000000..070c779b5ea --- /dev/null +++ b/tests/spa_unit/src/com/android/settings/network/telephony/scan/NetworkScanRepositoryTest.kt @@ -0,0 +1,265 @@ +/* + * Copyright (C) 2024 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.network.telephony.scan + +import android.content.Context +import android.telephony.AccessNetworkConstants.AccessNetworkType +import android.telephony.CellIdentityCdma +import android.telephony.CellIdentityGsm +import android.telephony.CellIdentityLte +import android.telephony.CellInfoCdma +import android.telephony.CellInfoGsm +import android.telephony.CellInfoLte +import android.telephony.NetworkScan +import android.telephony.NetworkScanRequest +import android.telephony.PhoneCapability +import android.telephony.TelephonyManager +import android.telephony.TelephonyManager.NETWORK_CLASS_BITMASK_5G +import android.telephony.TelephonyScanManager +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.android.settings.network.telephony.scan.NetworkScanRepository.NetworkScanCellInfos +import com.android.settings.network.telephony.scan.NetworkScanRepository.NetworkScanComplete +import com.android.settings.network.telephony.scan.NetworkScanRepository.NetworkScanError +import com.android.settingslib.spa.testutils.firstWithTimeoutOrNull +import com.android.settingslib.spa.testutils.toListWithTimeout +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.async +import kotlinx.coroutines.delay +import kotlinx.coroutines.runBlocking +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.kotlin.any +import org.mockito.kotlin.argThat +import org.mockito.kotlin.doAnswer +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import org.mockito.kotlin.spy +import org.mockito.kotlin.stub +import org.mockito.kotlin.verify + +@RunWith(AndroidJUnit4::class) +class NetworkScanRepositoryTest { + + private var callback: TelephonyScanManager.NetworkScanCallback? = null + + private val mockTelephonyManager = mock { + on { createForSubscriptionId(SUB_ID) } doReturn mock + on { requestNetworkScan(any(), any(), any()) } doAnswer { + callback = it.arguments[2] as TelephonyScanManager.NetworkScanCallback + mock() + } + } + + private val context: Context = spy(ApplicationProvider.getApplicationContext()) { + on { getSystemService(TelephonyManager::class.java) } doReturn mockTelephonyManager + } + + private val repository = NetworkScanRepository(context, SUB_ID) + + @Test + fun networkScanFlow_initial() = runBlocking { + val result = repository.networkScanFlow().firstWithTimeoutOrNull() + + assertThat(result).isNull() + } + + @Test + fun networkScanFlow_onResults(): Unit = runBlocking { + val cellInfos = listOf(CellInfoCdma().apply { cellIdentity = CELL_IDENTITY_CDMA }) + val listDeferred = async { + repository.networkScanFlow().toListWithTimeout() + } + delay(100) + + callback?.onResults(cellInfos) + + assertThat(listDeferred.await()).containsExactly(NetworkScanCellInfos(cellInfos)) + } + + @Test + fun networkScanFlow_onComplete(): Unit = runBlocking { + val listDeferred = async { + repository.networkScanFlow().toListWithTimeout() + } + delay(100) + + callback?.onComplete() + + assertThat(listDeferred.await()).containsExactly(NetworkScanComplete) + } + + @Test + fun networkScanFlow_onError(): Unit = runBlocking { + val listDeferred = async { + repository.networkScanFlow().toListWithTimeout() + } + delay(100) + + callback?.onError(1) + + assertThat(listDeferred.await()).containsExactly(NetworkScanError(1)) + } + + @Test + fun networkScanFlow_hasDuplicateItems(): Unit = runBlocking { + val cellInfos = listOf( + createCellInfoLte("123", false), + createCellInfoLte("123", false), + createCellInfoLte("124", true), + createCellInfoLte("124", true), + createCellInfoGsm("123", false), + createCellInfoGsm("123", false), + ) + val listDeferred = async { + repository.networkScanFlow().toListWithTimeout() + } + delay(100) + + callback?.onResults(cellInfos) + + assertThat(listDeferred.await()).containsExactly( + NetworkScanCellInfos( + listOf( + createCellInfoLte("123", false), + createCellInfoLte("124", true), + createCellInfoGsm("123", false), + ) + ) + ) + } + + + @Test + fun networkScanFlow_noDuplicateItems(): Unit = runBlocking { + val cellInfos = listOf( + createCellInfoLte("123", false), + createCellInfoLte("123", true), + createCellInfoLte("124", false), + createCellInfoLte("124", true), + createCellInfoGsm("456", false), + createCellInfoGsm("456", true), + ) + val listDeferred = async { + repository.networkScanFlow().toListWithTimeout() + } + delay(100) + + callback?.onResults(cellInfos) + + assertThat(listDeferred.await()).containsExactly( + NetworkScanCellInfos( + listOf( + createCellInfoLte("123", false), + createCellInfoLte("123", true), + createCellInfoLte("124", false), + createCellInfoLte("124", true), + createCellInfoGsm("456", false), + createCellInfoGsm("456", true), + ) + ) + ) + } + + @Test + fun createNetworkScan_deviceHasNrSa_requestNgran(): Unit = runBlocking { + mockTelephonyManager.stub { + on { getAllowedNetworkTypesBitmask() } doReturn NETWORK_CLASS_BITMASK_5G + on { getPhoneCapability() } doReturn + createPhoneCapability(intArrayOf(PhoneCapability.DEVICE_NR_CAPABILITY_SA)) + } + + repository.networkScanFlow().firstWithTimeoutOrNull() + + verify(mockTelephonyManager).requestNetworkScan(argThat { + specifiers.any { it.radioAccessNetwork == AccessNetworkType.NGRAN } + }, any(), any()) + } + + @Test + fun createNetworkScan_deviceNoNrSa_noNgran(): Unit = runBlocking { + mockTelephonyManager.stub { + on { getAllowedNetworkTypesBitmask() } doReturn NETWORK_CLASS_BITMASK_5G + on { getPhoneCapability() } doReturn + createPhoneCapability(intArrayOf(PhoneCapability.DEVICE_NR_CAPABILITY_NSA)) + } + + repository.networkScanFlow().firstWithTimeoutOrNull() + + verify(mockTelephonyManager).requestNetworkScan(argThat { + specifiers.none { it.radioAccessNetwork == AccessNetworkType.NGRAN } + }, any(), any()) + } + + private companion object { + const val SUB_ID = 1 + const val LONG = "Long" + const val SHORT = "Short" + + val CELL_IDENTITY_CDMA = CellIdentityCdma( + /* nid = */ 1, + /* sid = */ 2, + /* bid = */ 3, + /* lon = */ 4, + /* lat = */ 5, + /* alphal = */ LONG, + /* alphas = */ SHORT, + ) + + private fun createCellInfoLte(alphaLong: String, registered: Boolean): CellInfoLte { + val cellIdentityLte = CellIdentityLte( + /* ci = */ 1, + /* pci = */ 2, + /* tac = */ 3, + /* earfcn = */ 4, + /* bands = */ intArrayOf(1, 2), + /* bandwidth = */ 10000, + /* mccStr = */ null, + /* mncStr = */ null, + /* alphal = */ alphaLong, + /* alphas = */ null, + /* additionalPlmns = */ emptyList(), + /* csgInfo = */ null, + ) + return CellInfoLte().apply { + cellIdentity = cellIdentityLte + isRegistered = registered + } + } + + private fun createCellInfoGsm(alphaLong: String, registered: Boolean): CellInfoGsm { + val cellIdentityGsm = CellIdentityGsm( + /* lac = */ 1, + /* cid = */ 2, + /* arfcn = */ 3, + /* bsic = */ 4, + /* mccStr = */ "123", + /* mncStr = */ "01", + /* alphal = */ alphaLong, + /* alphas = */ null, + /* additionalPlmns = */ emptyList(), + ) + return CellInfoGsm().apply { + cellIdentity = cellIdentityGsm + isRegistered = registered + } + } + + private fun createPhoneCapability(deviceNrCapabilities: IntArray) = + PhoneCapability.Builder().setDeviceNrCapabilities(deviceNrCapabilities).build() + } +} diff --git a/tests/spa_unit/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProviderTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProviderTest.kt index dfacca892eb..b859df457ac 100644 --- a/tests/spa_unit/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProviderTest.kt +++ b/tests/spa_unit/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProviderTest.kt @@ -32,7 +32,11 @@ import com.android.settingslib.spa.testutils.FakeNavControllerWrapper import com.android.settingslib.spa.testutils.firstWithTimeoutOrNull import com.android.settingslib.spaprivileged.template.app.AppListItemModel import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.test.StandardTestDispatcher +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.advanceUntilIdle import kotlinx.coroutines.test.runTest import org.junit.Rule import org.junit.Test @@ -45,6 +49,8 @@ import org.junit.runner.RunWith class UserAspectRatioAppsPageProviderTest { @get:Rule val composeTestRule = createComposeRule() + private val testDispatcher = StandardTestDispatcher() + private val testScope = TestScope(testDispatcher) private val context: Context = ApplicationProvider.getApplicationContext() private val fakeNavControllerWrapper = FakeNavControllerWrapper() @@ -137,33 +143,37 @@ class UserAspectRatioAppsPageProviderTest { } } + @OptIn(ExperimentalCoroutinesApi::class) @Test - fun aspectRatioAppListModel_getSummaryDefault() { - val summary = getSummary(USER_MIN_ASPECT_RATIO_UNSET) + fun aspectRatioAppListModel_getSummaryDefault() = testScope.runTest { + val summary = setSummary(USER_MIN_ASPECT_RATIO_UNSET) + advanceUntilIdle() - assertThat(summary).isEqualTo(context.getString(R.string.user_aspect_ratio_app_default)) + assertThat(summary()).isEqualTo(context.getString(R.string.user_aspect_ratio_app_default)) } + @OptIn(ExperimentalCoroutinesApi::class) @Test - fun aspectRatioAppListModel_getSummaryWhenSplitScreen() { - val summary = getSummary(USER_MIN_ASPECT_RATIO_SPLIT_SCREEN) + fun aspectRatioAppListModel_getSummaryWhenSplitScreen() = testScope.runTest { + val summary = setSummary(USER_MIN_ASPECT_RATIO_SPLIT_SCREEN) + advanceUntilIdle() - assertThat(summary).isEqualTo(context.getString(R.string.user_aspect_ratio_half_screen)) + assertThat(summary()).isEqualTo(context.getString(R.string.user_aspect_ratio_half_screen)) } - private fun getSummary(userOverride: Int): String { - val listModel = UserAspectRatioAppListModel(context) + private fun setSummary(userOverride: Int): () -> String { + val listModel = UserAspectRatioAppListModel(context, testDispatcher) + val record = UserAspectRatioAppListItemModel( + app = APP, + userOverride = userOverride, + suggested = false, + canDisplay = true, + ) lateinit var summary: () -> String composeTestRule.setContent { - summary = listModel.getSummary(option = 0, - record = UserAspectRatioAppListItemModel( - app = APP, - userOverride = userOverride, - suggested = false, - canDisplay = true, - )) + summary = listModel.getSummary(option = 0, record = record) } - return summary() + return summary } diff --git a/tests/uitests/src/com/android/settings/ui/SecuritySettingsTest.kt b/tests/uitests/src/com/android/settings/ui/SecuritySettingsTest.kt index b5a4fe989cc..b792959acba 100644 --- a/tests/uitests/src/com/android/settings/ui/SecuritySettingsTest.kt +++ b/tests/uitests/src/com/android/settings/ui/SecuritySettingsTest.kt @@ -49,7 +49,8 @@ class SecuritySettingsTest { } @Test - @RequiresFlagsEnabled(Flags.FLAG_ALLOW_PRIVATE_PROFILE) + @RequiresFlagsEnabled(Flags.FLAG_ALLOW_PRIVATE_PROFILE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES) fun privateSpace_ifFlagON() { device.assertHasTexts(listOf("Private Space")) } diff --git a/tests/uitests/src/com/android/settings/ui/privatespace/PrivateSpaceAuthenticationActivityTest.kt b/tests/uitests/src/com/android/settings/ui/privatespace/PrivateSpaceAuthenticationActivityTest.kt index 8eadd9dde92..14feb49adc1 100644 --- a/tests/uitests/src/com/android/settings/ui/privatespace/PrivateSpaceAuthenticationActivityTest.kt +++ b/tests/uitests/src/com/android/settings/ui/privatespace/PrivateSpaceAuthenticationActivityTest.kt @@ -38,7 +38,8 @@ import org.junit.runner.RunWith @RunWith(AndroidJUnit4::class) -@RequiresFlagsEnabled(Flags.FLAG_ALLOW_PRIVATE_PROFILE) +@RequiresFlagsEnabled(Flags.FLAG_ALLOW_PRIVATE_PROFILE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES) class PrivateSpaceAuthenticationActivityTest { private val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) diff --git a/tests/unit/src/com/android/settings/biometrics/combination/CombinedBiometricStatusUtilsTest.java b/tests/unit/src/com/android/settings/biometrics/combination/CombinedBiometricStatusUtilsTest.java index a671a45b448..3a330f21a23 100644 --- a/tests/unit/src/com/android/settings/biometrics/combination/CombinedBiometricStatusUtilsTest.java +++ b/tests/unit/src/com/android/settings/biometrics/combination/CombinedBiometricStatusUtilsTest.java @@ -310,7 +310,8 @@ public class CombinedBiometricStatusUtilsTest { when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(false); mSetFlagsRule.enableFlags( android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE, - android.multiuser.Flags.FLAG_ENABLE_BIOMETRICS_TO_UNLOCK_PRIVATE_SPACE); + android.multiuser.Flags.FLAG_ENABLE_BIOMETRICS_TO_UNLOCK_PRIVATE_SPACE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); assertThat(mCombinedBiometricStatusUtils.getPrivateProfileSettingsClassName()) .isEqualTo(Settings.PrivateSpaceBiometricSettingsActivity.class.getName()); diff --git a/tests/unit/src/com/android/settings/development/quarantine/QuarantinedAppStateBridgeTest.java b/tests/unit/src/com/android/settings/development/quarantine/QuarantinedAppStateBridgeTest.java deleted file mode 100644 index 707d2b9f215..00000000000 --- a/tests/unit/src/com/android/settings/development/quarantine/QuarantinedAppStateBridgeTest.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2023 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.development.quarantine; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import android.content.Context; -import android.content.pm.PackageManager; -import android.os.UserHandle; - -import androidx.test.ext.junit.runners.AndroidJUnit4; - -import com.android.settingslib.applications.ApplicationsState.AppEntry; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -@RunWith(AndroidJUnit4.class) -public class QuarantinedAppStateBridgeTest { - private static final String TEST_PACKAGE = "com.example.test.pkg"; - private static final int TEST_APP_ID = 1234; - private static final int TEST_USER_ID_1 = 0; - private static final int TEST_USER_ID_2 = 10; - - @Mock - private Context mContext; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - } - - @Test - public void updateExtraInfo_packageQuarantined() throws Exception { - setPackageQuarantined(TEST_PACKAGE, TEST_USER_ID_1, false); - setPackageQuarantined(TEST_PACKAGE, TEST_USER_ID_2, true); - - final QuarantinedAppStateBridge bridge = - new QuarantinedAppStateBridge(mContext, null, null); - final AppEntry entry = mock(AppEntry.class); - - bridge.updateExtraInfo(entry, TEST_PACKAGE, UserHandle.getUid(TEST_USER_ID_2, TEST_APP_ID)); - assertThat(entry.extraInfo).isEqualTo(true); - } - - @Test - public void updateExtraInfo_packageNotQuarantined() throws Exception { - setPackageQuarantined(TEST_PACKAGE, TEST_USER_ID_1, false); - setPackageQuarantined(TEST_PACKAGE, TEST_USER_ID_2, false); - - final QuarantinedAppStateBridge bridge = - new QuarantinedAppStateBridge(mContext, null, null); - final AppEntry entry = mock(AppEntry.class); - - bridge.updateExtraInfo(entry, TEST_PACKAGE, UserHandle.getUid(TEST_USER_ID_2, TEST_APP_ID)); - assertThat(entry.extraInfo).isEqualTo(false); - } - - private void setPackageQuarantined(String packageName, int userId, boolean quarantined) - throws Exception { - final Context userContext = mock(Context.class); - when(mContext.createContextAsUser(eq(UserHandle.of(userId)), anyInt())) - .thenReturn(userContext); - final PackageManager packageManager = mock(PackageManager.class); - when(userContext.getPackageManager()).thenReturn(packageManager); - when(packageManager.isPackageQuarantined(packageName)).thenReturn(quarantined); - } -} diff --git a/tests/unit/src/com/android/settings/development/quarantine/QuarantinedAppsPreferenceControllerTest.java b/tests/unit/src/com/android/settings/development/quarantine/QuarantinedAppsPreferenceControllerTest.java deleted file mode 100644 index 33e43929715..00000000000 --- a/tests/unit/src/com/android/settings/development/quarantine/QuarantinedAppsPreferenceControllerTest.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2023 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.development.quarantine; - -import static com.android.settings.core.BasePreferenceController.AVAILABLE; -import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE; - -import static org.junit.Assert.assertEquals; - -import android.content.Context; -import android.content.pm.Flags; -import android.platform.test.annotations.RequiresFlagsDisabled; -import android.platform.test.annotations.RequiresFlagsEnabled; -import android.platform.test.flag.junit.CheckFlagsRule; -import android.platform.test.flag.junit.DeviceFlagsValueProvider; - -import androidx.test.ext.junit.runners.AndroidJUnit4; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -@RunWith(AndroidJUnit4.class) -public class QuarantinedAppsPreferenceControllerTest { - - private static final String PREF_KEY = "quarantined_apps"; - - @Rule - public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); - - @Mock - private Context mContext; - private QuarantinedAppsPreferenceController mController; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - mController = new QuarantinedAppsPreferenceController(mContext, PREF_KEY); - } - - @Test - @RequiresFlagsEnabled(Flags.FLAG_QUARANTINED_ENABLED) - public void testAvailabilityStatus_flagEnabled() { - assertEquals(mController.getAvailabilityStatus(), AVAILABLE); - } - - @Test - @RequiresFlagsDisabled(Flags.FLAG_QUARANTINED_ENABLED) - public void testAvailabilityStatus_flagDisabled() { - assertEquals(mController.getAvailabilityStatus(), CONDITIONALLY_UNAVAILABLE); - } -} diff --git a/tests/unit/src/com/android/settings/network/telephony/MobileNetworkSwitchControllerTest.java b/tests/unit/src/com/android/settings/network/telephony/MobileNetworkSwitchControllerTest.java deleted file mode 100644 index ae10ca84700..00000000000 --- a/tests/unit/src/com/android/settings/network/telephony/MobileNetworkSwitchControllerTest.java +++ /dev/null @@ -1,275 +0,0 @@ -/* - * Copyright (C) 2020 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.network.telephony; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.doReturn; -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.content.Intent; -import android.os.Bundle; -import android.os.Looper; -import android.platform.test.flag.junit.SetFlagsRule; -import android.telephony.SubscriptionInfo; -import android.telephony.SubscriptionManager; -import android.telephony.TelephonyCallback; -import android.telephony.TelephonyManager; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.LinearLayout; - -import androidx.preference.PreferenceManager; -import androidx.preference.PreferenceScreen; -import androidx.preference.PreferenceViewHolder; -import androidx.test.annotation.UiThreadTest; -import androidx.test.core.app.ApplicationProvider; - -import com.android.settings.flags.Flags; -import com.android.settings.network.SubscriptionUtil; -import com.android.settings.widget.SettingsMainSwitchPreference; - -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnit; -import org.mockito.junit.MockitoRule; - -import java.util.Arrays; -import java.util.concurrent.Executor; - -public class MobileNetworkSwitchControllerTest { - @Rule - public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); - @Rule - public final MockitoRule mMockitoRule = MockitoJUnit.rule(); - - @Mock - private SubscriptionManager mSubscriptionManager; - @Mock - private SubscriptionInfo mSubscription; - @Mock - private TelephonyManager mTelephonyManager; - - private PreferenceScreen mScreen; - private PreferenceManager mPreferenceManager; - private SettingsMainSwitchPreference mSwitchBar; - private Context mContext; - private MobileNetworkSwitchController mController; - private int mSubId = 123; - - @Before - public void setUp() { - mSetFlagsRule.disableFlags(Flags.FLAG_IS_DUAL_SIM_ONBOARDING_ENABLED); - - if (Looper.myLooper() == null) { - Looper.prepare(); - } - mContext = spy(ApplicationProvider.getApplicationContext()); - when(mContext.getSystemService(SubscriptionManager.class)).thenReturn(mSubscriptionManager); - when(mSubscriptionManager.setSubscriptionEnabled(eq(mSubId), anyBoolean())) - .thenReturn(true); - - when(mSubscription.isEmbedded()).thenReturn(true); - when(mSubscription.getSubscriptionId()).thenReturn(mSubId); - // Most tests want to have 2 available subscriptions so that the switch bar will show. - final SubscriptionInfo sub2 = mock(SubscriptionInfo.class); - when(sub2.getSubscriptionId()).thenReturn(456); - SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(mSubscription, sub2)); - - when(mContext.getSystemService(TelephonyManager.class)).thenReturn(mTelephonyManager); - when(mTelephonyManager.createForSubscriptionId(mSubId)) - .thenReturn(mTelephonyManager); - - final String key = "prefKey"; - mController = new MobileNetworkSwitchController(mContext, key); - mController.init(mSubscription.getSubscriptionId()); - - mPreferenceManager = new PreferenceManager(mContext); - mScreen = mPreferenceManager.createPreferenceScreen(mContext); - mSwitchBar = new SettingsMainSwitchPreference(mContext); - mSwitchBar.setKey(key); - mSwitchBar.setTitle("123"); - mScreen.addPreference(mSwitchBar); - - final LayoutInflater inflater = LayoutInflater.from(mContext); - final View view = inflater.inflate(mSwitchBar.getLayoutResource(), - new LinearLayout(mContext), false); - final PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(view); - mSwitchBar.onBindViewHolder(holder); - } - - @After - public void cleanUp() { - SubscriptionUtil.setAvailableSubscriptionsForTesting(null); - } - - @Test - @UiThreadTest - public void isAvailable_pSIM_isNotAvailable() { - when(mSubscription.isEmbedded()).thenReturn(false); - mController.displayPreference(mScreen); - assertThat(mSwitchBar.isShowing()).isFalse(); - - when(mSubscriptionManager.canDisablePhysicalSubscription()).thenReturn(true); - mController.displayPreference(mScreen); - assertThat(mSwitchBar.isShowing()).isTrue(); - } - - @Test - @UiThreadTest - public void displayPreference_oneEnabledSubscription_switchBarNotHidden() { - doReturn(true).when(mSubscriptionManager).isActiveSubscriptionId(mSubId); - SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(mSubscription)); - mController.displayPreference(mScreen); - assertThat(mSwitchBar.isShowing()).isTrue(); - } - - @Test - @UiThreadTest - public void displayPreference_oneDisabledSubscription_switchBarNotHidden() { - doReturn(false).when(mSubscriptionManager).isActiveSubscriptionId(mSubId); - SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(mSubscription)); - - mController.displayPreference(mScreen); - - assertThat(mSwitchBar.isShowing()).isTrue(); - } - - @Test - @UiThreadTest - public void displayPreference_subscriptionEnabled_switchIsOn() { - when(mSubscriptionManager.isActiveSubscriptionId(mSubId)).thenReturn(true); - mController.displayPreference(mScreen); - assertThat(mSwitchBar.isShowing()).isTrue(); - assertThat(mSwitchBar.isChecked()).isTrue(); - } - - @Test - @UiThreadTest - public void displayPreference_subscriptionDisabled_switchIsOff() { - when(mSubscriptionManager.isActiveSubscriptionId(mSubId)).thenReturn(false); - - mController.displayPreference(mScreen); - - assertThat(mSwitchBar.isShowing()).isTrue(); - assertThat(mSwitchBar.isChecked()).isFalse(); - } - - @Test - @UiThreadTest - public void switchChangeListener_fromEnabledToDisabled_setSubscriptionEnabledCalledCorrectly() { - when(mSubscriptionManager.isActiveSubscriptionId(mSubId)).thenReturn(true); - mController.displayPreference(mScreen); - assertThat(mSwitchBar.isShowing()).isTrue(); - assertThat(mSwitchBar.isChecked()).isTrue(); - - final ArgumentCaptor intentCaptor = ArgumentCaptor.forClass(Intent.class); - doNothing().when(mContext).startActivity(intentCaptor.capture()); - - // set switch off then should start a Activity. - mSwitchBar.setChecked(false); - - when(mSubscriptionManager.isActiveSubscriptionId(mSubId)).thenReturn(false); - // Simulate action of back from previous activity. - mController.displayPreference(mScreen); - Bundle extra = intentCaptor.getValue().getExtras(); - - verify(mContext, times(1)).startActivity(any()); - assertThat(extra.getInt(ToggleSubscriptionDialogActivity.ARG_SUB_ID)).isEqualTo(mSubId); - assertThat(extra.getBoolean(ToggleSubscriptionDialogActivity.ARG_enable)) - .isEqualTo(false); - assertThat(mSwitchBar.isChecked()).isFalse(); - } - - @Test - @UiThreadTest - public void switchChangeListener_fromEnabledToDisabled_setSubscriptionEnabledFailed() { - when(mSubscriptionManager.setSubscriptionEnabled(eq(mSubId), anyBoolean())) - .thenReturn(false); - when(mSubscriptionManager.isActiveSubscriptionId(mSubId)).thenReturn(true); - mController.displayPreference(mScreen); - assertThat(mSwitchBar.isShowing()).isTrue(); - assertThat(mSwitchBar.isChecked()).isTrue(); - - final ArgumentCaptor intentCaptor = ArgumentCaptor.forClass(Intent.class); - doNothing().when(mContext).startActivity(intentCaptor.capture()); - - // set switch off then should start a Activity. - mSwitchBar.setChecked(false); - - // Simulate action of back from previous activity. - mController.displayPreference(mScreen); - Bundle extra = intentCaptor.getValue().getExtras(); - - verify(mContext, times(1)).startActivity(any()); - assertThat(extra.getInt(ToggleSubscriptionDialogActivity.ARG_SUB_ID)).isEqualTo(mSubId); - assertThat(extra.getBoolean(ToggleSubscriptionDialogActivity.ARG_enable)) - .isEqualTo(false); - assertThat(mSwitchBar.isChecked()).isTrue(); - } - - @Test - @UiThreadTest - public void switchChangeListener_fromDisabledToEnabled_setSubscriptionEnabledCalledCorrectly() { - when(mSubscriptionManager.isActiveSubscriptionId(mSubId)).thenReturn(false); - mController.displayPreference(mScreen); - assertThat(mSwitchBar.isShowing()).isTrue(); - assertThat(mSwitchBar.isChecked()).isFalse(); - - final ArgumentCaptor intentCaptor = ArgumentCaptor.forClass(Intent.class); - doNothing().when(mContext).startActivity(intentCaptor.capture()); - mSwitchBar.setChecked(true); - Bundle extra = intentCaptor.getValue().getExtras(); - - verify(mContext, times(1)).startActivity(any()); - assertThat(extra.getInt(ToggleSubscriptionDialogActivity.ARG_SUB_ID)).isEqualTo(mSubId); - assertThat(extra.getBoolean(ToggleSubscriptionDialogActivity.ARG_enable)).isEqualTo(true); - } - @Test - @UiThreadTest - public void onResumeAndonPause_registerAndUnregisterTelephonyCallback() { - mController.onResume(); - - verify(mTelephonyManager) - .registerTelephonyCallback(any(Executor.class), any(TelephonyCallback.class)); - - mController.onPause(); - verify(mTelephonyManager) - .unregisterTelephonyCallback(any(TelephonyCallback.class)); - } - - @Test - @UiThreadTest - public void onPause_doNotRegisterAndUnregisterTelephonyCallback() { - mController.onPause(); - verify(mTelephonyManager, times(0)) - .unregisterTelephonyCallback(any(TelephonyCallback.class)); - } -} diff --git a/tests/unit/src/com/android/settings/network/telephony/NetworkScanHelperTest.java b/tests/unit/src/com/android/settings/network/telephony/NetworkScanHelperTest.java deleted file mode 100644 index f046c9a6f22..00000000000 --- a/tests/unit/src/com/android/settings/network/telephony/NetworkScanHelperTest.java +++ /dev/null @@ -1,260 +0,0 @@ -/* - * 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.network.telephony; - -import static com.google.common.truth.Truth.assertThat; - -import static org.junit.Assert.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.doReturn; -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.telephony.AccessNetworkConstants; -import android.telephony.CellInfo; -import android.telephony.ModemInfo; -import android.telephony.NetworkScan; -import android.telephony.NetworkScanRequest; -import android.telephony.PhoneCapability; -import android.telephony.RadioAccessSpecifier; -import android.telephony.TelephonyManager; -import android.telephony.TelephonyScanManager; - -import androidx.test.ext.junit.runners.AndroidJUnit4; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.Executor; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -@RunWith(AndroidJUnit4.class) -public class NetworkScanHelperTest { - - @Mock - private TelephonyManager mTelephonyManager; - @Mock - private List mCellInfos; - @Mock - private NetworkScanHelper.NetworkScanCallback mNetworkScanCallback; - - private static final long THREAD_EXECUTION_TIMEOUT_MS = 3000L; - - private ExecutorService mNetworkScanExecutor; - private NetworkScanHelper mNetworkScanHelper; - - private static final int SCAN_ID = 1234; - private static final int SUB_ID = 1; - - private NetworkScan mNetworkScan; - - public class NetworkScanMock extends NetworkScan { - NetworkScanMock(int scanId, int subId) { - super(scanId, subId); - } - - @Override - public void stopScan() { - return; - } - } - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - - mNetworkScanExecutor = Executors.newFixedThreadPool(1); - - mNetworkScanHelper = new NetworkScanHelper(mTelephonyManager, - mNetworkScanCallback, mNetworkScanExecutor); - - mNetworkScan = spy(new NetworkScanMock(SCAN_ID, SUB_ID)); - } - - @Test - public void startNetworkScan_incrementalAndSuccess_completionWithResult() { - when(mCellInfos.size()).thenReturn(1); - - doAnswer(new Answer() { - @Override - public Object answer(InvocationOnMock invocation) throws Throwable { - TelephonyScanManager.NetworkScanCallback callback = - (TelephonyScanManager.NetworkScanCallback) - (invocation.getArguments()[2]); - callback.onResults(mCellInfos); - callback.onComplete(); - return mNetworkScan; - } - }).when(mTelephonyManager).requestNetworkScan( - any(NetworkScanRequest.class), any(Executor.class), - any(TelephonyScanManager.NetworkScanCallback.class)); - - ArgumentCaptor> argument = ArgumentCaptor.forClass(List.class); - - startNetworkScan_incremental(true); - - verify(mNetworkScanCallback, times(1)).onResults(argument.capture()); - List actualResult = argument.getValue(); - assertThat(actualResult.size()).isEqualTo(mCellInfos.size()); - verify(mNetworkScanCallback, times(1)).onComplete(); - } - - @Test - public void startNetworkScan_incrementalAndImmediateFailure_failureWithErrorCode() { - doReturn(null).when(mTelephonyManager).requestNetworkScan( - any(NetworkScanRequest.class), any(Executor.class), - any(TelephonyScanManager.NetworkScanCallback.class)); - - startNetworkScan_incremental(true); - - verify(mNetworkScanCallback, times(1)).onError(anyInt()); - } - - @Test - public void startNetworkScan_incrementalAndFailure_failureWithErrorCode() { - doAnswer(new Answer() { - @Override - public Object answer(InvocationOnMock invocation) throws Throwable { - TelephonyScanManager.NetworkScanCallback callback = - (TelephonyScanManager.NetworkScanCallback) - (invocation.getArguments()[2]); - callback.onError(NetworkScan.ERROR_MODEM_ERROR); - return mNetworkScan; - } - }).when(mTelephonyManager).requestNetworkScan( - any(NetworkScanRequest.class), any(Executor.class), - any(TelephonyScanManager.NetworkScanCallback.class)); - - startNetworkScan_incremental(true); - - verify(mNetworkScanCallback, times(1)).onError(anyInt()); - } - - @Test - public void startNetworkScan_incrementalAndAbort_doStop() { - doReturn(mNetworkScan).when(mTelephonyManager).requestNetworkScan( - any(NetworkScanRequest.class), any(Executor.class), - any(TelephonyScanManager.NetworkScanCallback.class)); - - startNetworkScan_incremental(false); - - verify(mNetworkScan, times(1)).stopScan(); - } - - @Test - public void createNetworkScanForPreferredAccessNetworks_deviceNoNrSa_noNgran() { - int[] deviceNrCapabilities = new int[]{PhoneCapability.DEVICE_NR_CAPABILITY_NSA}; - PhoneCapability phoneCapability = createPhoneCapability(deviceNrCapabilities); - doReturn(TelephonyManager.NETWORK_CLASS_BITMASK_2G - | TelephonyManager.NETWORK_CLASS_BITMASK_3G - | TelephonyManager.NETWORK_CLASS_BITMASK_4G - | TelephonyManager.NETWORK_CLASS_BITMASK_5G).when( - mTelephonyManager).getPreferredNetworkTypeBitmask(); - doReturn(phoneCapability).when(mTelephonyManager).getPhoneCapability(); - List radioAccessSpecifiers = new ArrayList<>(); - radioAccessSpecifiers.add( - new RadioAccessSpecifier(AccessNetworkConstants.AccessNetworkType.GERAN, null, - null)); - radioAccessSpecifiers.add( - new RadioAccessSpecifier(AccessNetworkConstants.AccessNetworkType.UTRAN, null, - null)); - radioAccessSpecifiers.add( - new RadioAccessSpecifier(AccessNetworkConstants.AccessNetworkType.EUTRAN, null, - null)); - NetworkScanRequest expectedNetworkScanRequest = createNetworkScanRequest( - radioAccessSpecifiers); - - assertEquals(expectedNetworkScanRequest, - mNetworkScanHelper.createNetworkScanForPreferredAccessNetworks()); - } - - @Test - public void createNetworkScanForPreferredAccessNetworks_deviceHasNrSa_hasNgran() { - int[] deviceNrCapabilities = new int[]{PhoneCapability.DEVICE_NR_CAPABILITY_NSA, - PhoneCapability.DEVICE_NR_CAPABILITY_SA}; - PhoneCapability phoneCapability = createPhoneCapability(deviceNrCapabilities); - doReturn(TelephonyManager.NETWORK_CLASS_BITMASK_2G - | TelephonyManager.NETWORK_CLASS_BITMASK_3G - | TelephonyManager.NETWORK_CLASS_BITMASK_4G - | TelephonyManager.NETWORK_CLASS_BITMASK_5G).when( - mTelephonyManager).getPreferredNetworkTypeBitmask(); - doReturn(phoneCapability).when(mTelephonyManager).getPhoneCapability(); - List radioAccessSpecifiers = new ArrayList<>(); - radioAccessSpecifiers.add( - new RadioAccessSpecifier(AccessNetworkConstants.AccessNetworkType.GERAN, null, - null)); - radioAccessSpecifiers.add( - new RadioAccessSpecifier(AccessNetworkConstants.AccessNetworkType.UTRAN, null, - null)); - radioAccessSpecifiers.add( - new RadioAccessSpecifier(AccessNetworkConstants.AccessNetworkType.EUTRAN, null, - null)); - radioAccessSpecifiers.add( - new RadioAccessSpecifier(AccessNetworkConstants.AccessNetworkType.NGRAN, null, - null)); - NetworkScanRequest expectedNetworkScanRequest = createNetworkScanRequest( - radioAccessSpecifiers); - - assertEquals(expectedNetworkScanRequest, - mNetworkScanHelper.createNetworkScanForPreferredAccessNetworks()); - } - - private PhoneCapability createPhoneCapability(int[] deviceNrCapabilities) { - int maxActiveVoiceCalls = 1; - int maxActiveData = 2; - ModemInfo modemInfo = new ModemInfo(1, 2, true, false); - List logicalModemList = new ArrayList<>(); - logicalModemList.add(modemInfo); - return new PhoneCapability(maxActiveVoiceCalls, maxActiveData, - logicalModemList, false, deviceNrCapabilities); - } - - private NetworkScanRequest createNetworkScanRequest( - List radioAccessSpecifiers) { - return new NetworkScanRequest( - NetworkScanRequest.SCAN_TYPE_ONE_SHOT, - radioAccessSpecifiers.toArray( - new RadioAccessSpecifier[radioAccessSpecifiers.size()]), - mNetworkScanHelper.SEARCH_PERIODICITY_SEC, - mNetworkScanHelper.MAX_SEARCH_TIME_SEC, - mNetworkScanHelper.INCREMENTAL_RESULTS, - mNetworkScanHelper.INCREMENTAL_RESULTS_PERIODICITY_SEC, - null /* List of PLMN ids (MCC-MNC) */); - } - - private void startNetworkScan_incremental(boolean waitForCompletion) { - mNetworkScanHelper.startNetworkScan( - NetworkScanHelper.NETWORK_SCAN_TYPE_INCREMENTAL_RESULTS); - if (!waitForCompletion) { - mNetworkScanHelper.stopNetworkQuery(); - } - } - -} diff --git a/tests/unit/src/com/android/settings/network/telephony/NetworkSelectSettingsTest.java b/tests/unit/src/com/android/settings/network/telephony/NetworkSelectSettingsTest.java index 512e48454f8..a4657cee8a0 100644 --- a/tests/unit/src/com/android/settings/network/telephony/NetworkSelectSettingsTest.java +++ b/tests/unit/src/com/android/settings/network/telephony/NetworkSelectSettingsTest.java @@ -83,7 +83,6 @@ public class NetworkSelectSettingsTest { public Context mContext; public PreferenceCategory mPreferenceCategory; - public boolean mIsAggregationEnabled = true; private TargetClass mNetworkSelectSettings; @@ -104,7 +103,6 @@ public class NetworkSelectSettingsTest { doReturn(mCellId2).when(mCellInfo2).getCellIdentity(); doReturn(mock(CellSignalStrength.class)).when(mCellInfo2).getCellSignalStrength(); doReturn(CARRIER_NAME2).when(mCellId2).getOperatorAlphaLong(); - mIsAggregationEnabled = true; mNetworkSelectSettings = spy(new TargetClass(this)); PersistableBundle config = new PersistableBundle(); @@ -176,11 +174,6 @@ public class NetworkSelectSettingsTest { return pref; } - @Override - protected boolean enableAggregation(Context context) { - return mTestEnv.mIsAggregationEnabled; - } - @Override protected int getSubId() { return SUB_ID; @@ -212,84 +205,7 @@ public class NetworkSelectSettingsTest { } @Test - public void doAggregation_hasDuplicateItemsDiffCellIdCase1_removeSamePlmnRatItem() { - mNetworkSelectSettings.onCreateInitialization(); - List testList = Arrays.asList( - createLteCellInfo(true, 123, "123", "232", "CarrierA"), - createLteCellInfo(true, 1234, "123", "232", "CarrierA"), - createGsmCellInfo(false, 123, "123", "232", "CarrierB")); - List expected = Arrays.asList( - createLteCellInfo(true, 123, "123", "232", "CarrierA"), - createGsmCellInfo(false, 123, "123", "232", "CarrierB")); - assertThat(mNetworkSelectSettings.doAggregation(testList)).isEqualTo(expected); - } - - @Test - public void doAggregation_hasDuplicateItemsDiffCellIdCase2_removeSamePlmnRatItem() { - mNetworkSelectSettings.onCreateInitialization(); - List testList = Arrays.asList( - createLteCellInfo(true, 123, "123", "232", "CarrierA"), - createGsmCellInfo(false, 123, "123", "232", "CarrierB"), - createLteCellInfo(false, 1234, "123", "232", "CarrierB"), - createGsmCellInfo(false, 1234, "123", "232", "CarrierB")); - List expected = Arrays.asList( - createLteCellInfo(true, 123, "123", "232", "CarrierA"), - createGsmCellInfo(false, 123, "123", "232", "CarrierB"), - createLteCellInfo(false, 1234, "123", "232", "CarrierB")); - assertThat(mNetworkSelectSettings.doAggregation(testList)).isEqualTo(expected); - } - - @Test - public void doAggregation_hasDuplicateItemsDiffMccMncCase1_removeSamePlmnRatItem() { - mNetworkSelectSettings.onCreateInitialization(); - List testList = Arrays.asList( - createLteCellInfo(true, 123, "123", "232", "CarrierA"), - createLteCellInfo(true, 123, "456", "232", "CarrierA"), - createGsmCellInfo(false, 123, "123", "232", "CarrierB")); - List expected = Arrays.asList( - createLteCellInfo(true, 123, "123", "232", "CarrierA"), - createGsmCellInfo(false, 123, "123", "232", "CarrierB")); - assertThat(mNetworkSelectSettings.doAggregation(testList)).isEqualTo(expected); - } - - @Test - public void doAggregation_hasDuplicateItemsDiffMccMncCase2_removeSamePlmnRatItem() { - mNetworkSelectSettings.onCreateInitialization(); - List testList = Arrays.asList( - createLteCellInfo(true, 123, "123", "232", "CarrierA"), - createGsmCellInfo(false, 123, "123", "232", "CarrierB"), - createLteCellInfo(false, 1234, "123", "232", "CarrierB"), - createGsmCellInfo(false, 123, "456", "232", "CarrierB")); - List expected = Arrays.asList( - createLteCellInfo(true, 123, "123", "232", "CarrierA"), - createGsmCellInfo(false, 123, "123", "232", "CarrierB"), - createLteCellInfo(false, 1234, "123", "232", "CarrierB")); - assertThat(mNetworkSelectSettings.doAggregation(testList)).isEqualTo(expected); - } - - @Test - public void doAggregation_hasDuplicateItemsDiffMccMncCase3_removeSamePlmnRatItem() { - PersistableBundle config = new PersistableBundle(); - config.putBoolean( - CarrierConfigManager.KEY_REMOVE_SATELLITE_PLMN_IN_MANUAL_NETWORK_SCAN_BOOL, false); - doReturn(config).when(mCarrierConfigManager).getConfigForSubId(eq(SUB_ID), - eq(CarrierConfigManager.KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL), - eq(CarrierConfigManager.KEY_REMOVE_SATELLITE_PLMN_IN_MANUAL_NETWORK_SCAN_BOOL)); - - mNetworkSelectSettings.onCreateInitialization(); - List testList = Arrays.asList( - createLteCellInfo(false, 123, "123", "232", "CarrierA"), - createLteCellInfo(false, 124, "123", "233", "CarrierA"), - createLteCellInfo(true, 125, "123", "234", "CarrierA"), - createGsmCellInfo(false, 126, "456", "232", "CarrierA")); - List expected = Arrays.asList( - createLteCellInfo(true, 125, "123", "234", "CarrierA"), - createGsmCellInfo(false, 126, "456", "232", "CarrierA")); - assertThat(mNetworkSelectSettings.doAggregation(testList)).isEqualTo(expected); - } - - @Test - public void doAggregation_filterOutSatellitePlmn_whenKeyIsTrue() { + public void filterOutSatellitePlmn_filterOutSatellitePlmn_whenKeyIsTrue() { PersistableBundle config = new PersistableBundle(); config.putBoolean( CarrierConfigManager.KEY_REMOVE_SATELLITE_PLMN_IN_MANUAL_NETWORK_SCAN_BOOL, true); @@ -313,11 +229,11 @@ public class NetworkSelectSettingsTest { List expected = Arrays.asList( createGsmCellInfo(false, 123, "123", "233", "CarrierB"), createLteCellInfo(false, 1234, "123", "234", "CarrierC")); - assertThat(mNetworkSelectSettings.doAggregation(testList)).isEqualTo(expected); + assertThat(mNetworkSelectSettings.filterOutSatellitePlmn(testList)).isEqualTo(expected); } @Test - public void doAggregation_filterOutSatellitePlmn_whenNoSatellitePlmnIsAvailable() { + public void filterOutSatellitePlmn_filterOutSatellitePlmn_whenNoSatellitePlmnIsAvailable() { PersistableBundle config = new PersistableBundle(); config.putBoolean( CarrierConfigManager.KEY_REMOVE_SATELLITE_PLMN_IN_MANUAL_NETWORK_SCAN_BOOL, true); @@ -345,17 +261,17 @@ public class NetworkSelectSettingsTest { createGsmCellInfo(false, 123, "123", "233", "CarrierB"), createLteCellInfo(false, 1234, "123", "234", "CarrierC"), createGsmCellInfo(false, 12345, "123", "235", "CarrierD")); - assertThat(mNetworkSelectSettings.doAggregation(testList)).isEqualTo(expected); + assertThat(mNetworkSelectSettings.filterOutSatellitePlmn(testList)).isEqualTo(expected); // Expect no filter out when KEY_REMOVE_SATELLITE_PLMN_IN_MANUAL_NETWORK_SCAN_BOOL is false. config.putBoolean( CarrierConfigManager.KEY_REMOVE_SATELLITE_PLMN_IN_MANUAL_NETWORK_SCAN_BOOL, false); mNetworkSelectSettings.onCreateInitialization(); - assertThat(mNetworkSelectSettings.doAggregation(testList)).isEqualTo(expected); + assertThat(mNetworkSelectSettings.filterOutSatellitePlmn(testList)).isEqualTo(expected); } @Test - public void doAggregation_filterOutSatellitePlmn_whenKeyIsFalse() { + public void filterOutSatellitePlmn_filterOutSatellitePlmn_whenKeyIsFalse() { PersistableBundle config = new PersistableBundle(); config.putBoolean( CarrierConfigManager.KEY_REMOVE_SATELLITE_PLMN_IN_MANUAL_NETWORK_SCAN_BOOL, true); @@ -381,7 +297,7 @@ public class NetworkSelectSettingsTest { createGsmCellInfo(false, 123, "123", "233", "CarrierB"), createLteCellInfo(false, 1234, "123", "234", "CarrierC"), createGsmCellInfo(false, 12345, "123", "235", "CarrierD")); - assertThat(mNetworkSelectSettings.doAggregation(testList)).isEqualTo(expected); + assertThat(mNetworkSelectSettings.filterOutSatellitePlmn(testList)).isEqualTo(expected); } private CellInfoLte createLteCellInfo(boolean registered, int cellId, String mcc, String mnc, diff --git a/tests/unit/src/com/android/settings/privatespace/FaceFingerprintUnlockControllerTest.java b/tests/unit/src/com/android/settings/privatespace/FaceFingerprintUnlockControllerTest.java index f1da363b5e9..857135f419f 100644 --- a/tests/unit/src/com/android/settings/privatespace/FaceFingerprintUnlockControllerTest.java +++ b/tests/unit/src/com/android/settings/privatespace/FaceFingerprintUnlockControllerTest.java @@ -75,7 +75,8 @@ public class FaceFingerprintUnlockControllerTest { public void getAvailabilityStatus_whenFlagsEnabled_returnsAvailable() { mSetFlagsRule.enableFlags( android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE, - android.multiuser.Flags.FLAG_ENABLE_BIOMETRICS_TO_UNLOCK_PRIVATE_SPACE); + android.multiuser.Flags.FLAG_ENABLE_BIOMETRICS_TO_UNLOCK_PRIVATE_SPACE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); assertThat(mFaceFingerprintUnlockController.isAvailable()).isEqualTo(true); } @@ -83,18 +84,33 @@ public class FaceFingerprintUnlockControllerTest { /** Tests that the controller is not available when Biometrics flag is not enabled. */ @Test public void getAvailabilityStatus_whenBiometricFlagDisabled_returnsFalse() { - mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE); + mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); mSetFlagsRule.disableFlags( android.multiuser.Flags.FLAG_ENABLE_BIOMETRICS_TO_UNLOCK_PRIVATE_SPACE); assertThat(mFaceFingerprintUnlockController.isAvailable()).isEqualTo(false); } - /** Tests that the controller is not available when private feature flag is not enabled. */ + /** + * Tests that the controller is not available when the main private space flag is not + * enabled. + */ @Test - public void getAvailabilityStatus_whenPrivateFlagDisabled_returnsFalse() { + public void getAvailabilityStatus_whenPsMainFlagDisabled_returnsFalse() { mSetFlagsRule.disableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE); mSetFlagsRule.enableFlags( + android.multiuser.Flags.FLAG_ENABLE_BIOMETRICS_TO_UNLOCK_PRIVATE_SPACE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); + + assertThat(mFaceFingerprintUnlockController.isAvailable()).isEqualTo(false); + } + + /** Tests that the controller is not available when private features flag is not enabled. */ + @Test + public void getAvailabilityStatus_whenPsFeaturesFlagDisabled_returnsFalse() { + mSetFlagsRule.disableFlags(android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); + mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE, android.multiuser.Flags.FLAG_ENABLE_BIOMETRICS_TO_UNLOCK_PRIVATE_SPACE); assertThat(mFaceFingerprintUnlockController.isAvailable()).isEqualTo(false); @@ -106,7 +122,8 @@ public class FaceFingerprintUnlockControllerTest { doReturn(false).when(mLockPatternUtils).isSeparateProfileChallengeEnabled(anyInt()); mSetFlagsRule.enableFlags( android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE, - android.multiuser.Flags.FLAG_ENABLE_BIOMETRICS_TO_UNLOCK_PRIVATE_SPACE); + android.multiuser.Flags.FLAG_ENABLE_BIOMETRICS_TO_UNLOCK_PRIVATE_SPACE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); mFaceFingerprintUnlockController.updateState(mPreference); assertThat(mPreference.isEnabled()).isFalse(); @@ -119,7 +136,8 @@ public class FaceFingerprintUnlockControllerTest { doReturn(true).when(mLockPatternUtils).isSeparateProfileChallengeEnabled(anyInt()); mSetFlagsRule.enableFlags( android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE, - android.multiuser.Flags.FLAG_ENABLE_BIOMETRICS_TO_UNLOCK_PRIVATE_SPACE); + android.multiuser.Flags.FLAG_ENABLE_BIOMETRICS_TO_UNLOCK_PRIVATE_SPACE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); mFaceFingerprintUnlockController.updateState(mPreference); assertThat(mPreference.isEnabled()).isTrue(); diff --git a/tests/unit/src/com/android/settings/privatespace/HidePrivateSpaceControllerTest.java b/tests/unit/src/com/android/settings/privatespace/HidePrivateSpaceControllerTest.java index 0abe3146f4f..b71547b65e2 100644 --- a/tests/unit/src/com/android/settings/privatespace/HidePrivateSpaceControllerTest.java +++ b/tests/unit/src/com/android/settings/privatespace/HidePrivateSpaceControllerTest.java @@ -40,7 +40,8 @@ import org.junit.Test; import org.junit.runner.RunWith; @RunWith(AndroidJUnit4.class) -@RequiresFlagsEnabled(Flags.FLAG_ALLOW_PRIVATE_PROFILE) +@RequiresFlagsEnabled({Flags.FLAG_ALLOW_PRIVATE_PROFILE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES}) public class HidePrivateSpaceControllerTest { @Rule public final CheckFlagsRule mCheckFlagsRule = diff --git a/tests/unit/src/com/android/settings/privatespace/HidePrivateSpaceSensitiveNotificationsControllerTest.java b/tests/unit/src/com/android/settings/privatespace/HidePrivateSpaceSensitiveNotificationsControllerTest.java index 1430dfd1736..88503a525b6 100644 --- a/tests/unit/src/com/android/settings/privatespace/HidePrivateSpaceSensitiveNotificationsControllerTest.java +++ b/tests/unit/src/com/android/settings/privatespace/HidePrivateSpaceSensitiveNotificationsControllerTest.java @@ -67,7 +67,8 @@ public class HidePrivateSpaceSensitiveNotificationsControllerTest { mSetFlagsRule.enableFlags( android.multiuser.Flags.FLAG_ENABLE_PS_SENSITIVE_NOTIFICATIONS_TOGGLE); - mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE); + mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); mPrivateProfileId = PrivateSpaceMaintainer.getInstance( mContext).getPrivateProfileHandle().getIdentifier(); @@ -143,7 +144,8 @@ public class HidePrivateSpaceSensitiveNotificationsControllerTest { public void getAvailabilityStatus_flagDisabled() { mSetFlagsRule.disableFlags( android.multiuser.Flags.FLAG_ENABLE_PS_SENSITIVE_NOTIFICATIONS_TOGGLE); - mSetFlagsRule.disableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE); + mSetFlagsRule.disableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 1); Settings.Secure.putInt(mContext.getContentResolver(), diff --git a/tests/unit/src/com/android/settings/privatespace/HidePrivateSpaceSummaryControllerTest.java b/tests/unit/src/com/android/settings/privatespace/HidePrivateSpaceSummaryControllerTest.java index 39f7b9cbfa8..ed072d32587 100644 --- a/tests/unit/src/com/android/settings/privatespace/HidePrivateSpaceSummaryControllerTest.java +++ b/tests/unit/src/com/android/settings/privatespace/HidePrivateSpaceSummaryControllerTest.java @@ -40,7 +40,8 @@ import org.junit.Test; import org.junit.runner.RunWith; @RunWith(AndroidJUnit4.class) -@RequiresFlagsEnabled(Flags.FLAG_ALLOW_PRIVATE_PROFILE) +@RequiresFlagsEnabled({Flags.FLAG_ALLOW_PRIVATE_PROFILE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES}) public class HidePrivateSpaceSummaryControllerTest { @Rule public final CheckFlagsRule mCheckFlagsRule = diff --git a/tests/unit/src/com/android/settings/privatespace/PrivateSpaceAuthenticationActivityTest.java b/tests/unit/src/com/android/settings/privatespace/PrivateSpaceAuthenticationActivityTest.java index 4c6feea36ab..8a7bd70e0ed 100644 --- a/tests/unit/src/com/android/settings/privatespace/PrivateSpaceAuthenticationActivityTest.java +++ b/tests/unit/src/com/android/settings/privatespace/PrivateSpaceAuthenticationActivityTest.java @@ -88,7 +88,8 @@ public class PrivateSpaceAuthenticationActivityTest { /** Tests that when Private does not exist setup flow is started. */ //TODO(b/307729746) Plan to add more tests for complete setup flow @Test - @RequiresFlagsEnabled(Flags.FLAG_ALLOW_PRIVATE_PROFILE) + @RequiresFlagsEnabled({Flags.FLAG_ALLOW_PRIVATE_PROFILE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES}) public void whenPrivateProfileDoesNotExist_triggersSetupFlow() { when(mPrivateSpaceMaintainer.doesPrivateSpaceExist()).thenReturn(false); diff --git a/tests/unit/src/com/android/settings/privatespace/PrivateSpaceLockControllerTest.java b/tests/unit/src/com/android/settings/privatespace/PrivateSpaceLockControllerTest.java index 0d9db7e477b..c203a3cd72f 100644 --- a/tests/unit/src/com/android/settings/privatespace/PrivateSpaceLockControllerTest.java +++ b/tests/unit/src/com/android/settings/privatespace/PrivateSpaceLockControllerTest.java @@ -80,7 +80,8 @@ public class PrivateSpaceLockControllerTest { /** Tests that the controller is always available. */ @Test public void getAvailabilityStatus_returnsAvailable() { - mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE); + mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); assertThat(mPrivateSpaceLockController.isAvailable()).isEqualTo(true); } @@ -89,7 +90,8 @@ public class PrivateSpaceLockControllerTest { @Test public void getSummary_whenScreenLock() { doReturn(false).when(mLockPatternUtils).isSeparateProfileChallengeEnabled(anyInt()); - mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE); + mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); mPrivateSpaceLockController.updateState(mPreference); assertThat(mPreference.isEnabled()).isFalse(); @@ -103,7 +105,8 @@ public class PrivateSpaceLockControllerTest { .when(mLockPatternUtils).isSeparateProfileChallengeEnabled(anyInt()); doReturn(CREDENTIAL_TYPE_PATTERN) .when(mLockPatternUtils).getCredentialTypeForUser(anyInt()); - mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE); + mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); mPrivateSpaceLockController.updateState(mPreference); assertThat(mPreference.isEnabled()).isTrue(); @@ -115,7 +118,8 @@ public class PrivateSpaceLockControllerTest { public void getSummary_whenProfileLockPin() { doReturn(true).when(mLockPatternUtils).isSeparateProfileChallengeEnabled(anyInt()); doReturn(CREDENTIAL_TYPE_PIN).when(mLockPatternUtils).getCredentialTypeForUser(anyInt()); - mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE); + mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); mPrivateSpaceLockController.updateState(mPreference); assertThat(mPreference.isEnabled()).isTrue(); @@ -129,7 +133,8 @@ public class PrivateSpaceLockControllerTest { .when(mLockPatternUtils).isSeparateProfileChallengeEnabled(anyInt()); doReturn(CREDENTIAL_TYPE_PASSWORD) .when(mLockPatternUtils).getCredentialTypeForUser(anyInt()); - mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE); + mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); mPrivateSpaceLockController.updateState(mPreference); assertThat(mPreference.isEnabled()).isTrue(); diff --git a/tests/unit/src/com/android/settings/privatespace/PrivateSpaceMaintainerTest.java b/tests/unit/src/com/android/settings/privatespace/PrivateSpaceMaintainerTest.java index 8510b11c9c6..50f67d3c55b 100644 --- a/tests/unit/src/com/android/settings/privatespace/PrivateSpaceMaintainerTest.java +++ b/tests/unit/src/com/android/settings/privatespace/PrivateSpaceMaintainerTest.java @@ -148,7 +148,8 @@ public class PrivateSpaceMaintainerTest { public void createPrivateSpace_psDoesNotExist_setsDefaultPsSensitiveNotificationsValue() { mSetFlagsRule.enableFlags( Flags.FLAG_ALLOW_PRIVATE_PROFILE, - android.multiuser.Flags.FLAG_ENABLE_PS_SENSITIVE_NOTIFICATIONS_TOGGLE); + android.multiuser.Flags.FLAG_ENABLE_PS_SENSITIVE_NOTIFICATIONS_TOGGLE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); PrivateSpaceMaintainer privateSpaceMaintainer = PrivateSpaceMaintainer.getInstance(mContext); privateSpaceMaintainer.deletePrivateSpace(); @@ -259,7 +260,8 @@ public class PrivateSpaceMaintainerTest { public void createPrivateSpace_psDoesNotExist_resetsPSAutoLockSettings() { mSetFlagsRule.enableFlags( Flags.FLAG_ALLOW_PRIVATE_PROFILE, - android.multiuser.Flags.FLAG_SUPPORT_AUTOLOCK_FOR_PRIVATE_SPACE); + android.multiuser.Flags.FLAG_SUPPORT_AUTOLOCK_FOR_PRIVATE_SPACE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); final int autoLockOption = 2; PrivateSpaceMaintainer privateSpaceMaintainer = PrivateSpaceMaintainer.getInstance(mContext); @@ -282,7 +284,8 @@ public class PrivateSpaceMaintainerTest { public void createPrivateSpace_psExists_doesNotResetPSAutoLockSettings() { mSetFlagsRule.enableFlags( Flags.FLAG_ALLOW_PRIVATE_PROFILE, - android.multiuser.Flags.FLAG_SUPPORT_AUTOLOCK_FOR_PRIVATE_SPACE); + android.multiuser.Flags.FLAG_SUPPORT_AUTOLOCK_FOR_PRIVATE_SPACE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); final int privateSpaceAutLockValue = 1; PrivateSpaceMaintainer privateSpaceMaintainer = PrivateSpaceMaintainer.getInstance(mContext); diff --git a/tests/unit/src/com/android/settings/privatespace/PrivateSpaceSafetySourceTest.java b/tests/unit/src/com/android/settings/privatespace/PrivateSpaceSafetySourceTest.java index cf9ea051ebf..940f70d58f4 100644 --- a/tests/unit/src/com/android/settings/privatespace/PrivateSpaceSafetySourceTest.java +++ b/tests/unit/src/com/android/settings/privatespace/PrivateSpaceSafetySourceTest.java @@ -86,7 +86,8 @@ public class PrivateSpaceSafetySourceTest { @Test public void onDeviceRebootedEvent_whenSafetyCenterEnabled_setsData() { when(mSafetyCenterManagerWrapper.isEnabled(mContext)).thenReturn(true); - mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE); + mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); PrivateSpaceSafetySource.setSafetySourceData(mContext, EVENT_TYPE_DEVICE_REBOOTED); @@ -98,7 +99,8 @@ public class PrivateSpaceSafetySourceTest { @Test public void setSafetySourceData_whenFeatureDisabled_setsNullData() { when(mSafetyCenterManagerWrapper.isEnabled(mContext)).thenReturn(true); - mSetFlagsRule.disableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE); + mSetFlagsRule.disableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); PrivateSpaceSafetySource.setSafetySourceData(mContext, EVENT_TYPE_DEVICE_REBOOTED); @@ -113,7 +115,8 @@ public class PrivateSpaceSafetySourceTest { @Test public void setSafetySourceData_setsEnabled() { when(mSafetyCenterManagerWrapper.isEnabled(mContext)).thenReturn(true); - mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE); + mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); PrivateSpaceSafetySource.setSafetySourceData(mContext, EVENT_TYPE_DEVICE_REBOOTED); @@ -129,7 +132,8 @@ public class PrivateSpaceSafetySourceTest { @Test public void setSafetySourceData_setsPsAuthenticatorIntent() { when(mSafetyCenterManagerWrapper.isEnabled(mContext)).thenReturn(true); - mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE); + mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); PrivateSpaceSafetySource.setSafetySourceData(mContext, EVENT_TYPE_DEVICE_REBOOTED); diff --git a/tests/unit/src/com/android/settings/privatespace/UseOneLockControllerTest.java b/tests/unit/src/com/android/settings/privatespace/UseOneLockControllerTest.java index 744a8ec8882..5c2a15cbd05 100644 --- a/tests/unit/src/com/android/settings/privatespace/UseOneLockControllerTest.java +++ b/tests/unit/src/com/android/settings/privatespace/UseOneLockControllerTest.java @@ -74,7 +74,8 @@ public class UseOneLockControllerTest { /** Tests that the controller is always available. */ @Test public void getAvailabilityStatus_returnsAvailable() { - mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE); + mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); assertThat(mUseOneLockController.getAvailabilityStatus()).isEqualTo(AVAILABLE); } @@ -87,7 +88,8 @@ public class UseOneLockControllerTest { .when(mLockPatternUtils).isSeparateProfileChallengeEnabled(anyInt()); doReturn(CREDENTIAL_TYPE_PATTERN) .when(mLockPatternUtils).getCredentialTypeForUser(anyInt()); - mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE); + mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); mUseOneLockController.updateState(mPreference); assertThat(mUseOneLockController.getSummary().toString()).isEqualTo("Pattern"); @@ -99,7 +101,8 @@ public class UseOneLockControllerTest { doReturn(true) .when(mLockPatternUtils).isSeparateProfileChallengeEnabled(anyInt()); doReturn(CREDENTIAL_TYPE_PIN).when(mLockPatternUtils).getCredentialTypeForUser(anyInt()); - mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE); + mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); mUseOneLockController.updateState(mPreference); assertThat(mUseOneLockController.getSummary().toString()).isEqualTo("PIN"); @@ -112,7 +115,8 @@ public class UseOneLockControllerTest { .when(mLockPatternUtils).isSeparateProfileChallengeEnabled(anyInt()); doReturn(CREDENTIAL_TYPE_PASSWORD) .when(mLockPatternUtils).getCredentialTypeForUser(anyInt()); - mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE); + mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); mUseOneLockController.updateState(mPreference); assertThat(mUseOneLockController.getSummary().toString()).isEqualTo("Password"); diff --git a/tests/unit/src/com/android/settings/privatespace/autolock/AutoLockPreferenceControllerTest.java b/tests/unit/src/com/android/settings/privatespace/autolock/AutoLockPreferenceControllerTest.java index 01381d8320b..45c2c7562ff 100644 --- a/tests/unit/src/com/android/settings/privatespace/autolock/AutoLockPreferenceControllerTest.java +++ b/tests/unit/src/com/android/settings/privatespace/autolock/AutoLockPreferenceControllerTest.java @@ -75,7 +75,8 @@ public class AutoLockPreferenceControllerTest { public void getAvailabilityStatus_withAutoLockFlagEnabled_returnsAvailable() { mSetFlagsRule.enableFlags( Flags.FLAG_ALLOW_PRIVATE_PROFILE, - android.multiuser.Flags.FLAG_SUPPORT_AUTOLOCK_FOR_PRIVATE_SPACE); + android.multiuser.Flags.FLAG_SUPPORT_AUTOLOCK_FOR_PRIVATE_SPACE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); assertThat(mAutoLockPreferenceController.getAvailabilityStatus()).isEqualTo(AVAILABLE); } @@ -83,7 +84,8 @@ public class AutoLockPreferenceControllerTest { /** Tests that the controller is not available when auto lock flag is off. */ @Test public void getAvailabilityStatus_withAutoLockFlagDisabled_returnsNull() { - mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE); + mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); mSetFlagsRule.disableFlags(android.multiuser.Flags.FLAG_SUPPORT_AUTOLOCK_FOR_PRIVATE_SPACE); assertThat(mAutoLockPreferenceController.getAvailabilityStatus()) @@ -98,7 +100,8 @@ public class AutoLockPreferenceControllerTest { public void getSummary_whenOptionEveryTimeDeviceLocks_returnsEveryTimeDeviceLocks() { mSetFlagsRule.enableFlags( Flags.FLAG_ALLOW_PRIVATE_PROFILE, - android.multiuser.Flags.FLAG_SUPPORT_AUTOLOCK_FOR_PRIVATE_SPACE); + android.multiuser.Flags.FLAG_SUPPORT_AUTOLOCK_FOR_PRIVATE_SPACE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); Settings.Secure.putInt( mContentResolver, @@ -116,7 +119,8 @@ public class AutoLockPreferenceControllerTest { public void getSummary_whenOptionAfter5MinutesOfInactivity_returnsAfter5MinutesOfInactivity() { mSetFlagsRule.enableFlags( Flags.FLAG_ALLOW_PRIVATE_PROFILE, - android.multiuser.Flags.FLAG_SUPPORT_AUTOLOCK_FOR_PRIVATE_SPACE); + android.multiuser.Flags.FLAG_SUPPORT_AUTOLOCK_FOR_PRIVATE_SPACE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); Settings.Secure.putInt( mContentResolver, @@ -131,7 +135,8 @@ public class AutoLockPreferenceControllerTest { public void getSummary_whenOptionNever_returnsNever() { mSetFlagsRule.enableFlags( Flags.FLAG_ALLOW_PRIVATE_PROFILE, - android.multiuser.Flags.FLAG_SUPPORT_AUTOLOCK_FOR_PRIVATE_SPACE); + android.multiuser.Flags.FLAG_SUPPORT_AUTOLOCK_FOR_PRIVATE_SPACE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); Settings.Secure.putInt( mContentResolver, diff --git a/tests/unit/src/com/android/settings/privatespace/autolock/AutoLockSettingsFragmentTest.java b/tests/unit/src/com/android/settings/privatespace/autolock/AutoLockSettingsFragmentTest.java index 971ca40c8e1..1c620c068f3 100644 --- a/tests/unit/src/com/android/settings/privatespace/autolock/AutoLockSettingsFragmentTest.java +++ b/tests/unit/src/com/android/settings/privatespace/autolock/AutoLockSettingsFragmentTest.java @@ -94,7 +94,8 @@ public class AutoLockSettingsFragmentTest { public void verifyMetricsConstant() { mSetFlagsRule.enableFlags( Flags.FLAG_ALLOW_PRIVATE_PROFILE, - android.multiuser.Flags.FLAG_SUPPORT_AUTOLOCK_FOR_PRIVATE_SPACE); + android.multiuser.Flags.FLAG_SUPPORT_AUTOLOCK_FOR_PRIVATE_SPACE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); assertThat(mFragment.getMetricsCategory()).isEqualTo(SettingsEnums.PRIVATE_SPACE_SETTINGS); } @@ -103,7 +104,8 @@ public class AutoLockSettingsFragmentTest { public void getCandidates_returnsCandidateInfoListWithAllKeys() { mSetFlagsRule.enableFlags( Flags.FLAG_ALLOW_PRIVATE_PROFILE, - android.multiuser.Flags.FLAG_SUPPORT_AUTOLOCK_FOR_PRIVATE_SPACE); + android.multiuser.Flags.FLAG_SUPPORT_AUTOLOCK_FOR_PRIVATE_SPACE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); mFragment.onAttach(mContext); final List candidates = mFragment.getCandidates(); @@ -120,7 +122,8 @@ public class AutoLockSettingsFragmentTest { public void getDefaultKey_returnsStoredAutoLockOptionsValue() { mSetFlagsRule.enableFlags( Flags.FLAG_ALLOW_PRIVATE_PROFILE, - android.multiuser.Flags.FLAG_SUPPORT_AUTOLOCK_FOR_PRIVATE_SPACE); + android.multiuser.Flags.FLAG_SUPPORT_AUTOLOCK_FOR_PRIVATE_SPACE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); mFragment.onAttach(mContext); @@ -144,7 +147,8 @@ public class AutoLockSettingsFragmentTest { public void setDefaultKey_storesCorrectAutoLockOptionValue() { mSetFlagsRule.enableFlags( Flags.FLAG_ALLOW_PRIVATE_PROFILE, - android.multiuser.Flags.FLAG_SUPPORT_AUTOLOCK_FOR_PRIVATE_SPACE); + android.multiuser.Flags.FLAG_SUPPORT_AUTOLOCK_FOR_PRIVATE_SPACE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); mFragment.onAttach(mContext); mFragment.setDefaultKey("2"); diff --git a/tests/unit/src/com/android/settings/privatespace/delete/DeletePrivateSpaceControllerTest.java b/tests/unit/src/com/android/settings/privatespace/delete/DeletePrivateSpaceControllerTest.java index 371ca240039..ed8decddf0e 100644 --- a/tests/unit/src/com/android/settings/privatespace/delete/DeletePrivateSpaceControllerTest.java +++ b/tests/unit/src/com/android/settings/privatespace/delete/DeletePrivateSpaceControllerTest.java @@ -58,7 +58,8 @@ public class DeletePrivateSpaceControllerTest { /** Tests that the controller is available when private space flag is enabled. */ @Test public void getAvailabilityStatus_whenPrivateFlagEnabled_returnsAvailable() { - mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE); + mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); assertThat(mDeletePrivateSpaceController.getAvailabilityStatus()).isEqualTo(AVAILABLE); } @@ -66,7 +67,8 @@ public class DeletePrivateSpaceControllerTest { /** Tests that the controller is not available when private space flag is disabled. */ @Test public void getAvailabilityStatus_whenPrivateFlagDisabled_returnsUnsupportedOnDevice() { - mSetFlagsRule.disableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE); + mSetFlagsRule.disableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); assertThat(mDeletePrivateSpaceController.getAvailabilityStatus()) .isEqualTo(UNSUPPORTED_ON_DEVICE); diff --git a/tests/unit/src/com/android/settings/privatespace/delete/PrivateSpaceDeleteFragmentTest.java b/tests/unit/src/com/android/settings/privatespace/delete/PrivateSpaceDeleteFragmentTest.java index 16ccbc451fc..5c48375c209 100644 --- a/tests/unit/src/com/android/settings/privatespace/delete/PrivateSpaceDeleteFragmentTest.java +++ b/tests/unit/src/com/android/settings/privatespace/delete/PrivateSpaceDeleteFragmentTest.java @@ -39,7 +39,8 @@ public class PrivateSpaceDeleteFragmentTest { @Test @UiThreadTest public void verifyMetricsConstant() { - mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE); + mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); mFragment = spy(new PrivateSpaceDeleteFragment()); assertThat(mFragment.getMetricsCategory()).isEqualTo(SettingsEnums.PRIVATE_SPACE_SETTINGS); } diff --git a/tests/unit/src/com/android/settings/privatespace/delete/PrivateSpaceDeletionProgressFragmentTest.java b/tests/unit/src/com/android/settings/privatespace/delete/PrivateSpaceDeletionProgressFragmentTest.java index 5c2ef23564b..ffc1edf0c28 100644 --- a/tests/unit/src/com/android/settings/privatespace/delete/PrivateSpaceDeletionProgressFragmentTest.java +++ b/tests/unit/src/com/android/settings/privatespace/delete/PrivateSpaceDeletionProgressFragmentTest.java @@ -77,7 +77,8 @@ public class PrivateSpaceDeletionProgressFragmentTest { @Test @UiThreadTest public void verifyMetricsConstant() { - mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE); + mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); assertThat(mFragment.getMetricsCategory()).isEqualTo(SettingsEnums.PRIVATE_SPACE_SETTINGS); } @@ -87,7 +88,8 @@ public class PrivateSpaceDeletionProgressFragmentTest { public void deletePrivateSpace_deletesPS() { PrivateSpaceDeletionProgressFragment spyFragment = spy(mFragment); doNothing().when(spyFragment).showSuccessfulDeletionToast(); - mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE); + mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); mPrivateSpaceMaintainer.createPrivateSpace(); spyFragment.deletePrivateSpace(); @@ -100,7 +102,8 @@ public class PrivateSpaceDeletionProgressFragmentTest { public void deletePrivateSpace_onDeletion_showsDeletedToast() { PrivateSpaceDeletionProgressFragment spyFragment = spy(mFragment); doNothing().when(spyFragment).showSuccessfulDeletionToast(); - mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE); + mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); mPrivateSpaceMaintainer.createPrivateSpace(); spyFragment.deletePrivateSpace(); @@ -123,7 +126,8 @@ public class PrivateSpaceDeletionProgressFragmentTest { spyFragment.setPrivateSpaceMaintainer(injector); doReturn(DELETE_PS_ERROR_INTERNAL).when(mPrivateSpaceMaintainerMock).deletePrivateSpace(); doNothing().when(spyFragment).showDeletionInternalErrorToast(); - mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE); + mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); spyFragment.deletePrivateSpace(); diff --git a/tests/unit/src/com/android/settings/safetycenter/SafetySourceBroadcastReceiverTest.java b/tests/unit/src/com/android/settings/safetycenter/SafetySourceBroadcastReceiverTest.java index 85bd0e2e7c6..cd4c3c64fe7 100644 --- a/tests/unit/src/com/android/settings/safetycenter/SafetySourceBroadcastReceiverTest.java +++ b/tests/unit/src/com/android/settings/safetycenter/SafetySourceBroadcastReceiverTest.java @@ -247,7 +247,8 @@ public class SafetySourceBroadcastReceiverTest { @Test public void onReceive_onRefresh_withPrivateSpaceFeatureDisabled_setsNullData() { when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true); - mSetFlagsRule.disableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE); + mSetFlagsRule.disableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); Intent intent = new Intent()