diff --git a/res/drawable/ic_android_vd_theme_24.xml b/res/drawable/ic_android_vd_theme_24.xml new file mode 100644 index 00000000000..65812090007 --- /dev/null +++ b/res/drawable/ic_android_vd_theme_24.xml @@ -0,0 +1,26 @@ + + + + + diff --git a/res/drawable/ic_database_vd_theme_24.xml b/res/drawable/ic_database_vd_theme_24.xml new file mode 100644 index 00000000000..713a65e9c57 --- /dev/null +++ b/res/drawable/ic_database_vd_theme_24.xml @@ -0,0 +1,25 @@ + + + + diff --git a/res/layout/private_space_pre_finish_delay.xml b/res/layout/private_space_pre_finish_delay.xml new file mode 100644 index 00000000000..3b620bf256a --- /dev/null +++ b/res/layout/private_space_pre_finish_delay.xml @@ -0,0 +1,29 @@ + + + + + \ No newline at end of file diff --git a/res/navigation/privatespace_main_context_nav.xml b/res/navigation/privatespace_main_context_nav.xml index 80cd3997c4b..b027d87e556 100644 --- a/res/navigation/privatespace_main_context_nav.xml +++ b/res/navigation/privatespace_main_context_nav.xml @@ -46,6 +46,13 @@ android:id="@+id/action_retry_profile_creation" app:destination="@id/ps_auto_advance_fragment"/> + + + @@ -64,7 +71,7 @@ android:label="fragment_ps_lock"> + app:destination="@id/ps_pre_finish_delay_fragment"/> - + diff --git a/res/values/strings.xml b/res/values/strings.xml index 0f62fc66c39..9fbce465110 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -1352,6 +1352,8 @@ Use screen lock Choose new lock + + Just a sec\u2026 All set! @@ -1378,12 +1380,6 @@ Set a password for your private space Set a pattern for your private space - - Apps and notifications - - Sensitive notifications on lock screen - - Show sensitive content when private space is unlocked Create a Google Account to help keep your data private @@ -4419,8 +4415,10 @@ Tap to click - - Tap dragging + + Tap dragging + + Tap and drag your finger on the touchpad to move objects Touchpad gestures @@ -11089,8 +11087,8 @@ ]]> - - Passwords, passkeys & autofill + + Passwords, passkeys & accounts diff --git a/res/xml/private_space_settings.xml b/res/xml/private_space_settings.xml index f9795990903..b1233b9d797 100644 --- a/res/xml/private_space_settings.xml +++ b/res/xml/private_space_settings.xml @@ -59,17 +59,6 @@ - - - - - - diff --git a/res/xml/storage_category_fragment.xml b/res/xml/storage_category_fragment.xml index 2c9588938a2..58bd89138df 100644 --- a/res/xml/storage_category_fragment.xml +++ b/res/xml/storage_category_fragment.xml @@ -61,19 +61,31 @@ android:title="@string/storage_documents_and_other" android:icon="@drawable/ic_folder_vd_theme_24" android:order="106"/> - - + android:order="107"/> + + + + + + android:order="204" /> diff --git a/res/xml/storage_dashboard_fragment.xml b/res/xml/storage_dashboard_fragment.xml index 7c0f3a6d195..fd866ad8604 100644 --- a/res/xml/storage_dashboard_fragment.xml +++ b/res/xml/storage_dashboard_fragment.xml @@ -80,19 +80,31 @@ android:title="@string/storage_documents_and_other" android:icon="@drawable/ic_folder_vd_theme_24" android:order="106"/> - - + android:order="107"/> + + + + + + android:order="204" /> diff --git a/res/xml/trackpad_settings.xml b/res/xml/trackpad_settings.xml index 6601036073f..fcd43a575c9 100644 --- a/res/xml/trackpad_settings.xml +++ b/res/xml/trackpad_settings.xml @@ -48,10 +48,10 @@ android:order="30" settings:keywords="@string/keywords_trackpad_bottom_right_tap"/> - diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java index d44d727390c..e067c730d60 100644 --- a/src/com/android/settings/Utils.java +++ b/src/com/android/settings/Utils.java @@ -54,8 +54,10 @@ import android.graphics.drawable.AdaptiveIconDrawable; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.VectorDrawable; +import android.hardware.biometrics.SensorProperties; import android.hardware.face.Face; import android.hardware.face.FaceManager; +import android.hardware.face.FaceSensorPropertiesInternal; import android.hardware.fingerprint.Fingerprint; import android.hardware.fingerprint.FingerprintManager; import android.net.ConnectivityManager; @@ -927,6 +929,23 @@ public final class Utils extends com.android.settingslib.Utils { return hasFingerprintHardware(context) && hasFaceHardware(context); } + /** + * Return true if face is supported as Class 2 biometrics and above on the device, false + * otherwise. + */ + public static boolean isFaceNotConvenienceBiometric(@NonNull Context context) { + FaceManager faceManager = getFaceManagerOrNull(context); + if (faceManager != null) { + final List faceProperties = + faceManager.getSensorPropertiesInternal(); + if (!faceProperties.isEmpty()) { + final FaceSensorPropertiesInternal props = faceProperties.get(0); + return props.sensorStrength != SensorProperties.STRENGTH_CONVENIENCE; + } + } + return false; + } + /** * Launches an intent which may optionally have a user id defined. * @param fragment Fragment to use to launch the activity. diff --git a/src/com/android/settings/applications/credentials/CredentialsPickerActivity.java b/src/com/android/settings/applications/credentials/CredentialsPickerActivity.java index 479a184752f..44dbac0afb7 100644 --- a/src/com/android/settings/applications/credentials/CredentialsPickerActivity.java +++ b/src/com/android/settings/applications/credentials/CredentialsPickerActivity.java @@ -54,7 +54,12 @@ public class CredentialsPickerActivity extends SettingsActivity { @Override protected void onCreate(Bundle savedInstanceState) { - injectFragmentIntoIntent(this, getIntent()); + final String packageName = getCallingPackage(); + final Intent intent = getIntent(); + + intent.putExtra(DefaultCombinedPicker.EXTRA_PACKAGE_NAME, packageName); + injectFragmentIntoIntent(this, intent); + super.onCreate(savedInstanceState); } diff --git a/src/com/android/settings/biometrics/face/FaceSettings.java b/src/com/android/settings/biometrics/face/FaceSettings.java index 197aca03e0b..3398c203c65 100644 --- a/src/com/android/settings/biometrics/face/FaceSettings.java +++ b/src/com/android/settings/biometrics/face/FaceSettings.java @@ -201,8 +201,9 @@ public class FaceSettings extends DashboardFragment { } mRemoveController.setUserId(mUserId); - // Don't show keyguard controller for work profile settings. - if (mUserManager.isManagedProfile(mUserId)) { + // Don't show keyguard controller for work and private profile settings. + if (mUserManager.isManagedProfile(mUserId) + || mUserManager.getUserInfo(mUserId).isPrivateProfile()) { removePreference(FaceSettingsKeyguardPreferenceController.KEY); removePreference(mLockscreenController.getPreferenceKey()); } diff --git a/src/com/android/settings/deviceinfo/storage/StorageAsyncLoader.java b/src/com/android/settings/deviceinfo/storage/StorageAsyncLoader.java index 54935ecf4de..4906cf2d8d8 100644 --- a/src/com/android/settings/deviceinfo/storage/StorageAsyncLoader.java +++ b/src/com/android/settings/deviceinfo/storage/StorageAsyncLoader.java @@ -30,8 +30,10 @@ import android.content.pm.UserInfo; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; +import android.os.Environment; import android.os.UserHandle; import android.os.UserManager; +import android.os.storage.StorageManager; import android.provider.MediaStore; import android.provider.MediaStore.Files.FileColumns; import android.provider.MediaStore.MediaColumns; @@ -94,6 +96,7 @@ public class StorageAsyncLoader media /* queryArgs */); result.audioSize = getFilesSize(info.id, MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, media /* queryArgs */); + result.systemSize = getSystemSize(); final Bundle documentsAndOtherQueryArgs = new Bundle(); documentsAndOtherQueryArgs.putString(ContentResolver.QUERY_ARG_SQL_SELECTION, @@ -140,6 +143,16 @@ public class StorageAsyncLoader } } + private long getSystemSize() { + try { + return mStatsManager.getTotalBytes(StorageManager.UUID_DEFAULT) + - Environment.getDataDirectory().getTotalSpace(); + } catch (IOException e) { + Log.e(TAG, "Exception in calculating System category size", e); + return 0; + } + } + private StorageResult getAppsAndGamesSize(int userId) { Log.d(TAG, "Loading apps"); final List applicationInfos = @@ -225,6 +238,7 @@ public class StorageAsyncLoader public long videosSize; public long documentsAndOtherSize; public long trashSize; + public long systemSize; public long cacheSize; public long duplicateCodeSize; diff --git a/src/com/android/settings/deviceinfo/storage/StorageCacheHelper.java b/src/com/android/settings/deviceinfo/storage/StorageCacheHelper.java index e6da454f2f1..50690cb0791 100644 --- a/src/com/android/settings/deviceinfo/storage/StorageCacheHelper.java +++ b/src/com/android/settings/deviceinfo/storage/StorageCacheHelper.java @@ -35,6 +35,7 @@ public class StorageCacheHelper { private static final String DOCUMENTS_AND_OTHER_SIZE_KEY = "documents_and_other_size_key"; private static final String TRASH_SIZE_KEY = "trash_size_key"; private static final String SYSTEM_SIZE_KEY = "system_size_key"; + private static final String TEMPORARY_FILES_SIZE_KEY = "temporary_files_size_key"; private static final String USED_SIZE_KEY = "used_size_key"; private final SharedPreferences mSharedPreferences; @@ -66,6 +67,7 @@ public class StorageCacheHelper { .putLong(DOCUMENTS_AND_OTHER_SIZE_KEY, data.documentsAndOtherSize) .putLong(TRASH_SIZE_KEY, data.trashSize) .putLong(SYSTEM_SIZE_KEY, data.systemSize) + .putLong(TEMPORARY_FILES_SIZE_KEY, data.temporaryFilesSize) .apply(); } @@ -109,6 +111,7 @@ public class StorageCacheHelper { result.documentsAndOtherSize = mSharedPreferences.getLong(DOCUMENTS_AND_OTHER_SIZE_KEY, 0); result.trashSize = mSharedPreferences.getLong(TRASH_SIZE_KEY, 0); result.systemSize = mSharedPreferences.getLong(SYSTEM_SIZE_KEY, 0); + result.temporaryFilesSize = mSharedPreferences.getLong(TEMPORARY_FILES_SIZE_KEY, 0); return result; } @@ -126,5 +129,6 @@ public class StorageCacheHelper { public long documentsAndOtherSize; public long trashSize; public long systemSize; + public long temporaryFilesSize; } } diff --git a/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java b/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java index fd424178f0c..62422ca1ea5 100644 --- a/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java +++ b/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java @@ -27,6 +27,7 @@ import android.content.pm.UserInfo; import android.content.res.TypedArray; import android.graphics.drawable.Drawable; import android.net.Uri; +import android.os.Build; import android.os.Bundle; import android.os.UserHandle; import android.os.UserManager; @@ -40,6 +41,7 @@ import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import androidx.fragment.app.Fragment; import androidx.preference.Preference; +import androidx.preference.PreferenceCategory; import androidx.preference.PreferenceScreen; import com.android.settings.R; @@ -52,6 +54,7 @@ import com.android.settings.core.SubSettingLauncher; import com.android.settings.dashboard.profileselector.ProfileSelectFragment; import com.android.settings.deviceinfo.StorageItemPreference; import com.android.settings.deviceinfo.storage.StorageUtils.SystemInfoFragment; +import com.android.settings.deviceinfo.storage.StorageUtils.TemporaryFilesInfoFragment; import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.core.AbstractPreferenceController; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; @@ -74,6 +77,7 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle private static final String TAG = "StorageItemPreference"; private static final String SYSTEM_FRAGMENT_TAG = "SystemInfo"; + private static final String TEMPORARY_FILES_FRAGMENT_TAG = "TemporaryFilesInfo"; @VisibleForTesting static final String PUBLIC_STORAGE_KEY = "pref_public_storage"; @@ -92,6 +96,10 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle @VisibleForTesting static final String SYSTEM_KEY = "pref_system"; @VisibleForTesting + static final String TEMPORARY_FILES_KEY = "temporary_files"; + @VisibleForTesting + static final String CATEGORY_SPLITTER = "storage_category_splitter"; + @VisibleForTesting static final String TRASH_KEY = "pref_trash"; @VisibleForTesting @@ -133,9 +141,13 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle @VisibleForTesting @Nullable StorageItemPreference mDocumentsAndOtherPreference; @VisibleForTesting + @Nullable StorageItemPreference mTrashPreference; + @VisibleForTesting @Nullable StorageItemPreference mSystemPreference; @VisibleForTesting - @Nullable StorageItemPreference mTrashPreference; + @Nullable StorageItemPreference mTemporaryFilesPreference; + @VisibleForTesting + @Nullable PreferenceCategory mCategorySplitterPreferenceCategory; private final int mProfileType; @@ -220,6 +232,13 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle dialog.setTargetFragment(mFragment, 0); dialog.show(mFragment.getFragmentManager(), SYSTEM_FRAGMENT_TAG); return true; + case TEMPORARY_FILES_KEY: + final TemporaryFilesInfoFragment temporaryFilesDialog = + new TemporaryFilesInfoFragment(); + temporaryFilesDialog.setTargetFragment(mFragment, 0); + temporaryFilesDialog.show(mFragment.getFragmentManager(), + TEMPORARY_FILES_FRAGMENT_TAG); + return true; case TRASH_KEY: launchTrashIntent(); return true; @@ -285,6 +304,8 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle mAppsPreference.setVisible(visible); mGamesPreference.setVisible(visible); mSystemPreference.setVisible(visible); + mTemporaryFilesPreference.setVisible(visible); + mCategorySplitterPreferenceCategory.setVisible(visible); mTrashPreference.setVisible(visible); // If we don't have a shared volume for our internal storage (or the shared volume isn't @@ -315,7 +336,6 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle mPrivateStorageItemPreferences.add(mAppsPreference); mPrivateStorageItemPreferences.add(mGamesPreference); mPrivateStorageItemPreferences.add(mDocumentsAndOtherPreference); - mPrivateStorageItemPreferences.add(mSystemPreference); mPrivateStorageItemPreferences.add(mTrashPreference); } mScreen.removePreference(mImagesPreference); @@ -324,7 +344,6 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle mScreen.removePreference(mAppsPreference); mScreen.removePreference(mGamesPreference); mScreen.removePreference(mDocumentsAndOtherPreference); - mScreen.removePreference(mSystemPreference); mScreen.removePreference(mTrashPreference); // Sort display order by size. @@ -361,6 +380,7 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle tintPreference(mGamesPreference); tintPreference(mDocumentsAndOtherPreference); tintPreference(mSystemPreference); + tintPreference(mTemporaryFilesPreference); tintPreference(mTrashPreference); } @@ -389,7 +409,9 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle mAppsPreference = screen.findPreference(APPS_KEY); mGamesPreference = screen.findPreference(GAMES_KEY); mDocumentsAndOtherPreference = screen.findPreference(DOCUMENTS_AND_OTHER_KEY); + mCategorySplitterPreferenceCategory = screen.findPreference(CATEGORY_SPLITTER); mSystemPreference = screen.findPreference(SYSTEM_KEY); + mTemporaryFilesPreference = screen.findPreference(TEMPORARY_FILES_KEY); mTrashPreference = screen.findPreference(TRASH_KEY); } @@ -417,6 +439,12 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle mTrashPreference.setStorageSize(storageCache.trashSize, mTotalSize, animate); if (mSystemPreference != null) { mSystemPreference.setStorageSize(storageCache.systemSize, mTotalSize, animate); + mSystemPreference.setTitle(mContext.getString(R.string.storage_os_name, + Build.VERSION.RELEASE)); + } + if (mTemporaryFilesPreference != null) { + mTemporaryFilesPreference.setStorageSize(storageCache.temporaryFilesSize, mTotalSize, + animate); } // Cache the size info if (result != null) { @@ -445,6 +473,7 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle storageCache.gamesSize = data.gamesSize; storageCache.documentsAndOtherSize = data.documentsAndOtherSize; storageCache.trashSize = data.trashSize; + storageCache.systemSize = data.systemSize; // Everything else that hasn't already been attributed is tracked as // belonging to system. long attributedSize = 0; @@ -460,7 +489,9 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle + otherData.allAppsExceptGamesSize; attributedSize -= otherData.duplicateCodeSize; } - storageCache.systemSize = Math.max(DataUnit.GIBIBYTES.toBytes(1), + // System size is equal for each user and should be added only once + attributedSize += data.systemSize; + storageCache.temporaryFilesSize = Math.max(DataUnit.GIBIBYTES.toBytes(1), mUsedBytes - attributedSize); return storageCache; } diff --git a/src/com/android/settings/deviceinfo/storage/StorageUtils.java b/src/com/android/settings/deviceinfo/storage/StorageUtils.java index 4b6a2c40fd8..5c4a4b40f2a 100644 --- a/src/com/android/settings/deviceinfo/storage/StorageUtils.java +++ b/src/com/android/settings/deviceinfo/storage/StorageUtils.java @@ -23,7 +23,6 @@ import android.content.Intent; import android.content.pm.ResolveInfo; import android.graphics.drawable.Drawable; import android.os.AsyncTask; -import android.os.Build; import android.os.Bundle; import android.os.storage.DiskInfo; import android.os.storage.StorageManager; @@ -34,6 +33,7 @@ import android.text.format.Formatter; import android.util.Log; import android.widget.Toast; +import androidx.annotation.NonNull; import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.Fragment; @@ -206,7 +206,7 @@ public class StorageUtils { /** Shows information about system storage. */ public static class SystemInfoFragment extends InstrumentedDialogFragment { /** Shows the fragment. */ - public static void show(Fragment parent) { + public static void show(@NonNull Fragment parent) { if (!parent.isAdded()) return; final SystemInfoFragment dialog = new SystemInfoFragment(); @@ -222,8 +222,33 @@ public class StorageUtils { @Override public Dialog onCreateDialog(Bundle savedInstanceState) { return new AlertDialog.Builder(getActivity()) - .setMessage(getContext().getString(R.string.storage_detail_dialog_system, - Build.VERSION.RELEASE_OR_PREVIEW_DISPLAY)) + .setMessage(getContext().getString(R.string.storage_os_detail_dialog_system)) + .setPositiveButton(android.R.string.ok, null) + .create(); + } + } + + /** Shows information about temporary system files. */ + public static class TemporaryFilesInfoFragment extends InstrumentedDialogFragment { + /** Shows the fragment. */ + public static void show(@NonNull Fragment parent) { + if (!parent.isAdded()) return; + + final TemporaryFilesInfoFragment dialog = new TemporaryFilesInfoFragment(); + dialog.setTargetFragment(parent, 0); + dialog.show(parent.getFragmentManager(), "temporaryFilesInfo"); + } + + @Override + public int getMetricsCategory() { + return SettingsEnums.DIALOG_TEMPORARY_FILES_INFO; + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + return new AlertDialog.Builder(getActivity()) + .setMessage(getContext().getString( + R.string.storage_other_files_detail_dialog_system)) .setPositiveButton(android.R.string.ok, null) .create(); } diff --git a/src/com/android/settings/privatespace/AutoAdvanceSetupFragment.java b/src/com/android/settings/privatespace/AutoAdvanceSetupFragment.java index 7d551eeaf89..14627ecbf25 100644 --- a/src/com/android/settings/privatespace/AutoAdvanceSetupFragment.java +++ b/src/com/android/settings/privatespace/AutoAdvanceSetupFragment.java @@ -60,7 +60,7 @@ public class AutoAdvanceSetupFragment extends InstrumentedFragment { private static final int ANIMATION_DURATION_MILLIS = 500; private static final int HEADER_TEXT_MAX_LINES = 4; private GlifLayout mRootView; - private Handler mHandler; + private static final Handler sHandler = new Handler(Looper.getMainLooper()); private int mScreenTitleIndex; private static final List> HEADER_ILLUSTRATION_PAIRS = ImmutableList.of( @@ -78,7 +78,7 @@ public class AutoAdvanceSetupFragment extends InstrumentedFragment { if (getActivity() != null) { if (++mScreenTitleIndex < HEADER_ILLUSTRATION_PAIRS.size()) { startFadeOutAnimation(); - mHandler.postDelayed(mUpdateScreenResources, DELAY_BETWEEN_SCREENS); + sHandler.postDelayed(mUpdateScreenResources, DELAY_BETWEEN_SCREENS); } else if (PrivateSpaceMaintainer.getInstance(getActivity()) .doesPrivateSpaceExist()) { mMetricsFeatureProvider.action( @@ -133,8 +133,6 @@ public class AutoAdvanceSetupFragment extends InstrumentedFragment { mRootView.getHeaderTextView().setBreakStrategy(BREAK_STRATEGY_SIMPLE); mRootView.getHeaderTextView().setAccessibilityLiveRegion(ACCESSIBILITY_LIVE_REGION_POLITE); updateHeaderAndIllustration(); - mHandler = new Handler(Looper.getMainLooper()); - mHandler.postDelayed(mUpdateScreenResources, DELAY_BETWEEN_SCREENS); OnBackPressedCallback callback = new OnBackPressedCallback(true /* enabled by default */) { @Override @@ -155,12 +153,16 @@ public class AutoAdvanceSetupFragment extends InstrumentedFragment { @Override public void onDestroy() { - if (mHandler != null) { - mHandler.removeCallbacks(mUpdateScreenResources); - } + sHandler.removeCallbacks(mUpdateScreenResources); super.onDestroy(); } + @Override + public void onResume() { + sHandler.postDelayed(mUpdateScreenResources, DELAY_BETWEEN_SCREENS); + super.onResume(); + } + @Override public int getMetricsCategory() { return SettingsEnums.PRIVATE_SPACE_SETUP_SPACE_CREATION; diff --git a/src/com/android/settings/privatespace/HidePrivateSpaceSensitiveNotificationsController.java b/src/com/android/settings/privatespace/HidePrivateSpaceSensitiveNotificationsController.java deleted file mode 100644 index 6cb54a1cd89..00000000000 --- a/src/com/android/settings/privatespace/HidePrivateSpaceSensitiveNotificationsController.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * 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.privatespace; - -import static android.provider.Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS; - -import android.content.Context; -import android.os.UserHandle; -import android.provider.Settings; - -import androidx.annotation.NonNull; - -import com.android.settings.core.TogglePreferenceController; - -import java.util.Objects; - -/** - * A controller object for sensitive notifications in Private Space settings page. - */ -public class HidePrivateSpaceSensitiveNotificationsController extends TogglePreferenceController { - private final PrivateSpaceMaintainer mPrivateSpaceMaintainer; - private final UserHandle mPrivateProfileId; - public static final int ENABLED = 1; - public static final int DISABLED = 0; - private static final int DEVICE_SENSITIVE_NOTIFICATIONS_DEFAULT = ENABLED; - private static final int DEVICE_LOCK_SCREEN_NOTIFICATIONS_DEFAULT = ENABLED; - private static final int PRIVATE_SPACE_SENSITIVE_NOTIFICATIONS_DEFAULT = DISABLED; - - public HidePrivateSpaceSensitiveNotificationsController(@NonNull Context context, - @NonNull String preferenceKey) { - super(context, preferenceKey); - mPrivateSpaceMaintainer = PrivateSpaceMaintainer.getInstance(context); - mPrivateProfileId = Objects.requireNonNull( - mPrivateSpaceMaintainer.getPrivateProfileHandle()); - } - - @Override - public int getAvailabilityStatus() { - if (!android.os.Flags.allowPrivateProfile() - || !android.multiuser.Flags.enablePsSensitiveNotificationsToggle() - || !android.multiuser.Flags.enablePrivateSpaceFeatures() - || !mPrivateSpaceMaintainer.doesPrivateSpaceExist()) { - return UNSUPPORTED_ON_DEVICE; - } - if (!getLockscreenNotificationsEnabled(mContext) - || !getLockscreenSensitiveNotificationsEnabledOnDevice(mContext)) { - return DISABLED_DEPENDENT_SETTING; - } - return AVAILABLE; - } - - @Override - public boolean isChecked() { - return Settings.Secure.getIntForUser(mContext.getContentResolver(), - LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, - PRIVATE_SPACE_SENSITIVE_NOTIFICATIONS_DEFAULT, mPrivateProfileId.getIdentifier()) - != DISABLED; - } - - @Override - public boolean setChecked(boolean isChecked) { - Settings.Secure.putIntForUser(mContext.getContentResolver(), - Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, - isChecked ? ENABLED : DISABLED, mPrivateProfileId.getIdentifier()); - return true; - } - - @Override - public int getSliceHighlightMenuRes() { - return 0; - } - - /** - * If notifications are disabled on the device, the toggle for private space sensitive - * notifications should be unavailable. - */ - private static boolean getLockscreenNotificationsEnabled(Context context) { - return Settings.Secure.getInt(context.getContentResolver(), - Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, - DEVICE_LOCK_SCREEN_NOTIFICATIONS_DEFAULT) != DISABLED; - } - - /** - * If sensitive notifications are hidden on the device, they should be hidden for private space - * also. - */ - private static boolean getLockscreenSensitiveNotificationsEnabledOnDevice(Context context) { - return Settings.Secure.getInt(context.getContentResolver(), - Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, - DEVICE_SENSITIVE_NOTIFICATIONS_DEFAULT) != DISABLED; - } -} diff --git a/src/com/android/settings/privatespace/PrivateSpaceMaintainer.java b/src/com/android/settings/privatespace/PrivateSpaceMaintainer.java index a0c4cbecaed..300cbdbb2fb 100644 --- a/src/com/android/settings/privatespace/PrivateSpaceMaintainer.java +++ b/src/com/android/settings/privatespace/PrivateSpaceMaintainer.java @@ -65,6 +65,8 @@ public class PrivateSpaceMaintainer { @Settings.Secure.PrivateSpaceAutoLockOption public static final int PRIVATE_SPACE_AUTO_LOCK_DEFAULT_VAL = PRIVATE_SPACE_AUTO_LOCK_AFTER_DEVICE_RESTART; + /** Default value for the hide private space sensitive notifications on lockscreen. */ + public static final int HIDE_PRIVATE_SPACE_SENSITIVE_NOTIFICATIONS_DISABLED_VAL = 0; public enum ErrorDeletingPrivateSpace { DELETE_PS_ERROR_NONE, @@ -287,6 +289,14 @@ public class PrivateSpaceMaintainer { } } + /** + * Returns true if private profile can be added to the device or if private space already + * exists, false otherwise. + */ + public boolean isPrivateSpaceEntryPointEnabled() { + return mUserManager.canAddPrivateProfile() || doesPrivateSpaceExist(); + } + /** Returns true if private space exists and is running, otherwise returns false */ @VisibleForTesting synchronized boolean isPrivateProfileRunning() { @@ -308,7 +318,7 @@ public class PrivateSpaceMaintainer { private void setPrivateSpaceSensitiveNotificationsDefaultValue() { Settings.Secure.putIntForUser(mContext.getContentResolver(), Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, - HidePrivateSpaceSensitiveNotificationsController.DISABLED, + HIDE_PRIVATE_SPACE_SENSITIVE_NOTIFICATIONS_DISABLED_VAL, mUserHandle.getIdentifier()); } diff --git a/src/com/android/settings/privatespace/PrivateSpaceSafetySource.java b/src/com/android/settings/privatespace/PrivateSpaceSafetySource.java index 3272f125756..9a018539b0e 100644 --- a/src/com/android/settings/privatespace/PrivateSpaceSafetySource.java +++ b/src/com/android/settings/privatespace/PrivateSpaceSafetySource.java @@ -52,9 +52,7 @@ public final class PrivateSpaceSafetySource { // Do not add the entry point when // -Private Profile is not present and // -Private Profile cannot be added. - if (!privateSpaceMaintainer.doesPrivateSpaceExist() - && userManager != null - && !userManager.canAddPrivateProfile()) { + if (!privateSpaceMaintainer.isPrivateSpaceEntryPointEnabled()) { Log.i(TAG, "Private Space not allowed for user " + context.getUser()); return; } diff --git a/src/com/android/settings/privatespace/PrivateSpaceSetLockFragment.java b/src/com/android/settings/privatespace/PrivateSpaceSetLockFragment.java index 399c2c82fbb..11f4bcb74e3 100644 --- a/src/com/android/settings/privatespace/PrivateSpaceSetLockFragment.java +++ b/src/com/android/settings/privatespace/PrivateSpaceSetLockFragment.java @@ -97,7 +97,7 @@ public class PrivateSpaceSetLockFragment extends InstrumentedFragment { getContext(), SettingsEnums.ACTION_PRIVATE_SPACE_SETUP_USE_SCREEN_LOCK); // Simply Use default screen lock. No need to handle NavHostFragment.findNavController(PrivateSpaceSetLockFragment.this) - .navigate(R.id.action_lock_success_fragment); + .navigate(R.id.action_pre_finish_delay_fragment); }; } diff --git a/src/com/android/settings/privatespace/PrivateSpaceSetupActivity.java b/src/com/android/settings/privatespace/PrivateSpaceSetupActivity.java index ec7132adf0e..4cbcac74646 100644 --- a/src/com/android/settings/privatespace/PrivateSpaceSetupActivity.java +++ b/src/com/android/settings/privatespace/PrivateSpaceSetupActivity.java @@ -60,7 +60,7 @@ public class PrivateSpaceSetupActivity extends FragmentActivity { @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { if (requestCode == SET_LOCK_ACTION && resultCode == RESULT_OK) { - mNavHostFragment.getNavController().navigate(R.id.action_success_fragment); + mNavHostFragment.getNavController().navigate(R.id.action_pre_finish_delay_fragment); } else if (requestCode == ACCOUNT_LOGIN_ACTION) { if (resultCode == RESULT_OK) { mMetricsFeatureProvider.action( diff --git a/src/com/android/settings/privatespace/SetupPreFinishDelayFragment.java b/src/com/android/settings/privatespace/SetupPreFinishDelayFragment.java new file mode 100644 index 00000000000..aee8512ec9b --- /dev/null +++ b/src/com/android/settings/privatespace/SetupPreFinishDelayFragment.java @@ -0,0 +1,136 @@ +/* + * 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.privatespace; + +import static android.content.Intent.ACTION_PROFILE_INACCESSIBLE; +import static android.content.Intent.ACTION_PROFILE_UNAVAILABLE; + +import android.app.settings.SettingsEnums; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.activity.OnBackPressedCallback; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.navigation.fragment.NavHostFragment; + +import com.android.settings.R; +import com.android.settings.core.InstrumentedFragment; + +import com.google.android.setupdesign.GlifLayout; + +public class SetupPreFinishDelayFragment extends InstrumentedFragment { + private static final String TAG = "SetupPreFinishDelayFrag"; + private static final Handler sHandler = new Handler(Looper.getMainLooper()); + private static final int MAX_DELAY_BEFORE_SETUP_FINISH = 5000; + private boolean mActionProfileUnavailable; + private boolean mActionProfileInaccessible; + + protected final BroadcastReceiver mBroadcastReceiver = + new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (intent == null) { + return; + } + String action = intent.getAction(); + Log.i(TAG, "Received broadcast: " + action); + if (ACTION_PROFILE_UNAVAILABLE.equals(action)) { + mActionProfileUnavailable = true; + } else if (ACTION_PROFILE_INACCESSIBLE.equals(action)) { + mActionProfileInaccessible = true; + } + if (mActionProfileUnavailable && mActionProfileInaccessible) { + showSetupSuccessScreen(); + } + } + }; + + private Runnable mRunnable = + () -> { + showSetupSuccessScreen(); + }; + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + if (android.os.Flags.allowPrivateProfile() + && android.multiuser.Flags.enablePrivateSpaceFeatures()) { + super.onCreate(savedInstanceState); + } + } + + @NonNull + @Override + public View onCreateView( + @NonNull LayoutInflater inflater, + @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + GlifLayout rootView = + (GlifLayout) + inflater.inflate(R.layout.private_space_pre_finish_delay, container, false); + OnBackPressedCallback callback = + new OnBackPressedCallback(true /* enabled by default */) { + @Override + public void handleOnBackPressed() { + // Handle the back button event. We intentionally don't want to allow back + // button to work in this screen during the setup flow. + } + }; + requireActivity().getOnBackPressedDispatcher().addCallback(this, callback); + if (savedInstanceState == null) { + // TODO(b/307729746): Add a test to verify PS is locked after setup completion. + PrivateSpaceMaintainer.getInstance(getActivity()).lockPrivateSpace(); + } + return rootView; + } + + @Override + public void onPause() { + super.onPause(); + getActivity().unregisterReceiver(mBroadcastReceiver); + } + + @Override + public void onResume() { + super.onResume(); + final IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(ACTION_PROFILE_UNAVAILABLE); + intentFilter.addAction(ACTION_PROFILE_INACCESSIBLE); + getActivity().registerReceiver(mBroadcastReceiver, intentFilter); + sHandler.postDelayed(mRunnable, MAX_DELAY_BEFORE_SETUP_FINISH); + } + + @Override + public int getMetricsCategory() { + return SettingsEnums.PRIVATE_SPACE_SETUP_PRE_FINISH; + } + + private void showSetupSuccessScreen() { + sHandler.removeCallbacks(mRunnable); + NavHostFragment.findNavController(SetupPreFinishDelayFragment.this) + .navigate(R.id.action_success_fragment); + } +} diff --git a/src/com/android/settings/privatespace/SetupSuccessFragment.java b/src/com/android/settings/privatespace/SetupSuccessFragment.java index c0a2cd4d87a..90be48ea9a4 100644 --- a/src/com/android/settings/privatespace/SetupSuccessFragment.java +++ b/src/com/android/settings/privatespace/SetupSuccessFragment.java @@ -87,8 +87,6 @@ public class SetupSuccessFragment extends InstrumentedFragment { if (activity != null) { mMetricsFeatureProvider.action( getContext(), SettingsEnums.ACTION_PRIVATE_SPACE_SETUP_DONE); - //TODO(b/307729746): Add a test to verify PS is locked after setup completion. - PrivateSpaceMaintainer.getInstance(activity).lockPrivateSpace(); Intent allAppsIntent = new Intent(Intent.ACTION_ALL_APPS); ResolveInfo resolveInfo = activity.getPackageManager() diff --git a/src/com/android/settings/privatespace/delete/ResetOptionsDeletePrivateSpaceController.java b/src/com/android/settings/privatespace/delete/ResetOptionsDeletePrivateSpaceController.java index 274bb2b184b..6e1f0df96d5 100644 --- a/src/com/android/settings/privatespace/delete/ResetOptionsDeletePrivateSpaceController.java +++ b/src/com/android/settings/privatespace/delete/ResetOptionsDeletePrivateSpaceController.java @@ -59,10 +59,9 @@ public class ResetOptionsDeletePrivateSpaceController extends BasePreferenceCont @Override public int getAvailabilityStatus() { - // TODO(b/330396315) : use canAddPrivateProfile() to check if private space is supported - // on the device return android.multiuser.Flags.enablePrivateSpaceFeatures() && android.multiuser.Flags.deletePrivateSpaceFromReset() + && isPrivateSpaceEntryPointEnabled() ? AVAILABLE : UNSUPPORTED_ON_DEVICE; } @@ -107,6 +106,11 @@ public class ResetOptionsDeletePrivateSpaceController extends BasePreferenceCont return mHostFragment.getFragmentManager(); } + @VisibleForTesting + boolean isPrivateSpaceEntryPointEnabled() { + return PrivateSpaceMaintainer.getInstance(mContext).isPrivateSpaceEntryPointEnabled(); + } + /* Dialog shown when deleting private space from Reset Options. */ public static class DeletePrivateSpaceDialogFragment extends InstrumentedDialogFragment { private static final String TAG = "PrivateSpaceResetFrag"; diff --git a/src/com/android/settings/privatespace/onelock/PrivateSpaceFacePreferenceController.java b/src/com/android/settings/privatespace/onelock/PrivateSpaceFacePreferenceController.java index 583a093dbc2..6ccaacb4b4d 100644 --- a/src/com/android/settings/privatespace/onelock/PrivateSpaceFacePreferenceController.java +++ b/src/com/android/settings/privatespace/onelock/PrivateSpaceFacePreferenceController.java @@ -64,8 +64,8 @@ public class PrivateSpaceFacePreferenceController extends BiometricFaceStatusPre @Override public int getAvailabilityStatus() { return android.os.Flags.allowPrivateProfile() - && android.multiuser.Flags.enableBiometricsToUnlockPrivateSpace() - && android.multiuser.Flags.enablePrivateSpaceFeatures() + && android.multiuser.Flags.enableBiometricsToUnlockPrivateSpace() + && android.multiuser.Flags.enablePrivateSpaceFeatures() ? AVAILABLE : UNSUPPORTED_ON_DEVICE; } @@ -87,7 +87,8 @@ public class PrivateSpaceFacePreferenceController extends BiometricFaceStatusPre public void displayPreference(@NonNull PreferenceScreen screen) { super.displayPreference(screen); Preference preference = screen.findPreference(getPreferenceKey()); - if (!Utils.isMultipleBiometricsSupported(mContext)) { + if (!Utils.isMultipleBiometricsSupported(mContext) + && Utils.isFaceNotConvenienceBiometric(mContext)) { preference.setTitle(R.string.private_space_face_title); } } diff --git a/src/com/android/settings/privatespace/onelock/PrivateSpaceFingerprintPreferenceController.java b/src/com/android/settings/privatespace/onelock/PrivateSpaceFingerprintPreferenceController.java index f88c9facccc..dd6518af67c 100644 --- a/src/com/android/settings/privatespace/onelock/PrivateSpaceFingerprintPreferenceController.java +++ b/src/com/android/settings/privatespace/onelock/PrivateSpaceFingerprintPreferenceController.java @@ -66,8 +66,8 @@ public class PrivateSpaceFingerprintPreferenceController @Override public int getAvailabilityStatus() { return android.os.Flags.allowPrivateProfile() - && android.multiuser.Flags.enableBiometricsToUnlockPrivateSpace() - && android.multiuser.Flags.enablePrivateSpaceFeatures() + && android.multiuser.Flags.enableBiometricsToUnlockPrivateSpace() + && android.multiuser.Flags.enablePrivateSpaceFeatures() ? AVAILABLE : UNSUPPORTED_ON_DEVICE; } @@ -89,7 +89,8 @@ public class PrivateSpaceFingerprintPreferenceController public void displayPreference(@NonNull PreferenceScreen screen) { super.displayPreference(screen); Preference preference = screen.findPreference(getPreferenceKey()); - if (!Utils.isMultipleBiometricsSupported(mContext)) { + if (!Utils.isMultipleBiometricsSupported(mContext) + || !Utils.isFaceNotConvenienceBiometric(mContext)) { preference.setTitle(R.string.private_space_fingerprint_title); } } diff --git a/src/com/android/settings/privatespace/onelock/UseOneLockSettingsFragment.java b/src/com/android/settings/privatespace/onelock/UseOneLockSettingsFragment.java index ce017e31152..bf5748e6e2b 100644 --- a/src/com/android/settings/privatespace/onelock/UseOneLockSettingsFragment.java +++ b/src/com/android/settings/privatespace/onelock/UseOneLockSettingsFragment.java @@ -73,13 +73,14 @@ public class UseOneLockSettingsFragment extends DashboardFragment { final List controllers = new ArrayList<>(); controllers.add(new UseOneLockControllerSwitch(context, this)); controllers.add(new PrivateSpaceLockController(context, this)); - if (Utils.isMultipleBiometricsSupported(context)) { + boolean isFaceAuthAllowed = Utils.isFaceNotConvenienceBiometric(context); + if (Utils.isMultipleBiometricsSupported(context) && isFaceAuthAllowed) { controllers.add(new FaceFingerprintUnlockController(context, getSettingsLifecycle())); } else if (Utils.hasFingerprintHardware(context)) { controllers.add( new PrivateSpaceFingerprintPreferenceController( context, "private_space_biometrics", getSettingsLifecycle())); - } else if (Utils.hasFaceHardware(context)) { + } else if (Utils.hasFaceHardware(context) && isFaceAuthAllowed) { controllers.add( new PrivateSpaceFacePreferenceController( context, "private_space_biometrics", getSettingsLifecycle())); diff --git a/tests/robotests/src/com/android/settings/UtilsTest.java b/tests/robotests/src/com/android/settings/UtilsTest.java index 0c555da2075..0c57b014506 100644 --- a/tests/robotests/src/com/android/settings/UtilsTest.java +++ b/tests/robotests/src/com/android/settings/UtilsTest.java @@ -16,6 +16,10 @@ package com.android.settings; +import static android.hardware.biometrics.SensorProperties.STRENGTH_CONVENIENCE; +import static android.hardware.biometrics.SensorProperties.STRENGTH_STRONG; +import static android.hardware.biometrics.SensorProperties.STRENGTH_WEAK; + import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertNull; @@ -43,6 +47,9 @@ import android.graphics.Color; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.VectorDrawable; +import android.hardware.face.FaceManager; +import android.hardware.face.FaceSensorProperties; +import android.hardware.face.FaceSensorPropertiesInternal; import android.net.ConnectivityManager; import android.net.LinkAddress; import android.net.LinkProperties; @@ -433,6 +440,69 @@ public class UtilsTest { assertNull(confirmCredentialString); } + @Test + public void isFaceNotConvenienceBiometric_faceStrengthStrong_shouldReturnTrue() { + FaceManager mockFaceManager = mock(FaceManager.class); + when(mContext.getSystemService(Context.FACE_SERVICE)).thenReturn(mockFaceManager); + doReturn(true).when(mPackageManager).hasSystemFeature(anyString()); + List props = List.of(new FaceSensorPropertiesInternal( + 0 /* id */, + STRENGTH_STRONG, + 1 /* maxTemplatesAllowed */, + new ArrayList<>() /* componentInfo */, + FaceSensorProperties.TYPE_UNKNOWN, + true /* supportsFaceDetection */, + true /* supportsSelfIllumination */, + false /* resetLockoutRequiresChallenge */)); + doReturn(props).when(mockFaceManager).getSensorPropertiesInternal(); + + assertThat(Utils.isFaceNotConvenienceBiometric(mContext)).isTrue(); + } + + @Test + public void isFaceNotConvenienceBiometric_faceStrengthWeak_shouldReturnTrue() { + FaceManager mockFaceManager = mock(FaceManager.class); + when(mContext.getSystemService(Context.FACE_SERVICE)).thenReturn(mockFaceManager); + doReturn(true).when(mPackageManager).hasSystemFeature(anyString()); + List props = List.of(new FaceSensorPropertiesInternal( + 0 /* id */, + STRENGTH_WEAK, + 1 /* maxTemplatesAllowed */, + new ArrayList<>() /* componentInfo */, + FaceSensorProperties.TYPE_UNKNOWN, + true /* supportsFaceDetection */, + true /* supportsSelfIllumination */, + false /* resetLockoutRequiresChallenge */)); + doReturn(props).when(mockFaceManager).getSensorPropertiesInternal(); + + assertThat(Utils.isFaceNotConvenienceBiometric(mContext)).isTrue(); + } + + @Test + public void isFaceNotConvenienceBiometric_faceStrengthConvenience_shouldReturnFalse() { + FaceManager mockFaceManager = mock(FaceManager.class); + when(mContext.getSystemService(Context.FACE_SERVICE)).thenReturn(mockFaceManager); + doReturn(true).when(mPackageManager).hasSystemFeature(anyString()); + List props = List.of(new FaceSensorPropertiesInternal( + 0 /* id */, + STRENGTH_CONVENIENCE, + 1 /* maxTemplatesAllowed */, + new ArrayList<>() /* componentInfo */, + FaceSensorProperties.TYPE_UNKNOWN, + true /* supportsFaceDetection */, + true /* supportsSelfIllumination */, + false /* resetLockoutRequiresChallenge */)); + doReturn(props).when(mockFaceManager).getSensorPropertiesInternal(); + + assertThat(Utils.isFaceNotConvenienceBiometric(mContext)).isFalse(); + } + + @Test + public void isFaceNotConvenienceBiometric_faceManagerNull_shouldReturnFalse() { + when(mContext.getSystemService(Context.FACE_SERVICE)).thenReturn(null); + assertThat(Utils.isFaceNotConvenienceBiometric(mContext)).isFalse(); + } + private void setUpForConfirmCredentialString(boolean isEffectiveUserManagedProfile) { when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mMockUserManager); when(mMockUserManager.getCredentialOwnerProfile(USER_ID)).thenReturn(USER_ID); diff --git a/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageCacheHelperTest.java b/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageCacheHelperTest.java index 9e20e78c03a..a26ea1dfca2 100644 --- a/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageCacheHelperTest.java +++ b/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageCacheHelperTest.java @@ -41,6 +41,7 @@ public class StorageCacheHelperTest { private static final long FAKE_TOTAL_SIZE = 256000L; private static final long FAKE_TOTAL_USED_SIZE = 50000L; private static final long FAKE_USED_SIZE = 6500L; + private static final long FAKE_TEMPORARY_FILES_SIZE = 2500L; private Context mContext; private StorageCacheHelper mHelper; @@ -70,6 +71,7 @@ public class StorageCacheHelperTest { StorageCacheHelper.StorageCache storageCache = mHelper.retrieveCachedSize(); assertThat(storageCache.imagesSize).isEqualTo(FAKE_IMAGES_SIZE); + assertThat(storageCache.temporaryFilesSize).isEqualTo(FAKE_TEMPORARY_FILES_SIZE); assertThat(storageCache.totalSize).isEqualTo(0); } @@ -100,6 +102,7 @@ public class StorageCacheHelperTest { result.gamesSize = FAKE_GAMES_SIZE; result.videosSize = FAKE_VIDEOS_SIZE; result.allAppsExceptGamesSize = FAKE_APPS_SIZE; + result.temporaryFilesSize = FAKE_TEMPORARY_FILES_SIZE; return result; } } diff --git a/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java index b61f5ab4ef4..2590f52340f 100644 --- a/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java @@ -45,6 +45,7 @@ import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentTransaction; +import androidx.preference.PreferenceCategory; import androidx.preference.PreferenceScreen; import com.android.settings.R; @@ -126,7 +127,10 @@ public class StorageItemPreferenceControllerTest { final StorageItemPreference documentsAndOther = spy(new StorageItemPreference(mContext)); documentsAndOther.setIcon(R.drawable.ic_folder_vd_theme_24); final StorageItemPreference system = spy(new StorageItemPreference(mContext)); - system.setIcon(com.android.settingslib.R.drawable.ic_system_update); + system.setIcon(R.drawable.ic_android_vd_theme_24); + final StorageItemPreference temporaryFiles = spy(new StorageItemPreference(mContext)); + temporaryFiles.setIcon(R.drawable.ic_database_vd_theme_24); + final PreferenceCategory categorySplitter = spy(new PreferenceCategory(mContext)); final StorageItemPreference trash = spy(new StorageItemPreference(mContext)); trash.setIcon(R.drawable.ic_trash_can); @@ -147,6 +151,10 @@ public class StorageItemPreferenceControllerTest { .thenReturn(documentsAndOther); when(screen.findPreference(eq(StorageItemPreferenceController.SYSTEM_KEY))) .thenReturn(system); + when(screen.findPreference(eq(StorageItemPreferenceController.TEMPORARY_FILES_KEY))) + .thenReturn(temporaryFiles); + when(screen.findPreference(eq(StorageItemPreferenceController.CATEGORY_SPLITTER))) + .thenReturn(categorySplitter); when(screen.findPreference(eq(StorageItemPreferenceController.TRASH_KEY))) .thenReturn(trash); @@ -219,6 +227,7 @@ public class StorageItemPreferenceControllerTest { assertThat(mController.mGamesPreference.isVisible()).isFalse(); assertThat(mController.mDocumentsAndOtherPreference.isVisible()).isFalse(); assertThat(mController.mSystemPreference.isVisible()).isFalse(); + assertThat(mController.mTemporaryFilesPreference.isVisible()).isFalse(); assertThat(mController.mTrashPreference.isVisible()).isFalse(); } @@ -329,6 +338,16 @@ public class StorageItemPreferenceControllerTest { .add(nullable(StorageUtils.SystemInfoFragment.class), nullable(String.class)); } + @Test + public void testClickTemporaryFiles() { + mPreference.setKey(StorageItemPreferenceController.TEMPORARY_FILES_KEY); + assertThat(mController.handlePreferenceTreeClick(mPreference)).isTrue(); + + verify(mFragment.getFragmentManager().beginTransaction()) + .add(nullable(StorageUtils.TemporaryFilesInfoFragment.class), + nullable(String.class)); + } + @Test @Config(shadows = ShadowUserManager.class) public void testMeasurementCompletedUpdatesPreferences() { @@ -343,6 +362,7 @@ public class StorageItemPreferenceControllerTest { result.documentsAndOtherSize = MEGABYTE_IN_BYTES * 50; result.trashSize = KILOBYTE_IN_BYTES * 100; result.allAppsExceptGamesSize = MEGABYTE_IN_BYTES * 90; + result.systemSize = MEGABYTE_IN_BYTES * 60; final SparseArray results = new SparseArray<>(); results.put(0, result); @@ -356,6 +376,8 @@ public class StorageItemPreferenceControllerTest { assertThat(mController.mDocumentsAndOtherPreference.getSummary().toString()) .isEqualTo("50 MB"); assertThat(mController.mTrashPreference.getSummary().toString()).isEqualTo("100 kB"); + assertThat(mController.mSystemPreference.getSummary().toString()) + .isEqualTo("60 MB"); } @Test @@ -373,6 +395,7 @@ public class StorageItemPreferenceControllerTest { verify(mController.mDocumentsAndOtherPreference, times(2)) .setIcon(nullable(Drawable.class)); verify(mController.mSystemPreference, times(2)).setIcon(nullable(Drawable.class)); + verify(mController.mTemporaryFilesPreference, times(2)).setIcon(nullable(Drawable.class)); verify(mController.mTrashPreference, times(2)).setIcon(nullable(Drawable.class)); } @@ -437,6 +460,7 @@ public class StorageItemPreferenceControllerTest { assertThat(mController.mGamesPreference.isVisible()).isFalse(); assertThat(mController.mDocumentsAndOtherPreference.isVisible()).isFalse(); assertThat(mController.mSystemPreference.isVisible()).isFalse(); + assertThat(mController.mTemporaryFilesPreference.isVisible()).isFalse(); assertThat(mController.mTrashPreference.isVisible()).isFalse(); } diff --git a/tests/robotests/src/com/android/settings/privatespace/delete/ResetOptionsDeletePrivateSpaceControllerTest.java b/tests/robotests/src/com/android/settings/privatespace/delete/ResetOptionsDeletePrivateSpaceControllerTest.java index ebff07a44d3..a17859ad9ae 100644 --- a/tests/robotests/src/com/android/settings/privatespace/delete/ResetOptionsDeletePrivateSpaceControllerTest.java +++ b/tests/robotests/src/com/android/settings/privatespace/delete/ResetOptionsDeletePrivateSpaceControllerTest.java @@ -103,11 +103,23 @@ public class ResetOptionsDeletePrivateSpaceControllerTest { } @Test - public void getAvailabilityStatus_flagsEnabled_returnsAvailable() { + public void getAvailabilityStatus_flagsEnabledCanAddProfile_returnsAvailable() { mSetFlagsRule.enableFlags(android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); mSetFlagsRule.enableFlags(android.multiuser.Flags.FLAG_DELETE_PRIVATE_SPACE_FROM_RESET); + ResetOptionsDeletePrivateSpaceController spyController = spy(mController); + doReturn(true).when(spyController).isPrivateSpaceEntryPointEnabled(); - assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE); + assertThat(spyController.getAvailabilityStatus()).isEqualTo(AVAILABLE); + } + + @Test + public void getAvailabilityStatus_flagsEnabledCannotAddProfile_returnsUnsupported() { + mSetFlagsRule.enableFlags(android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); + mSetFlagsRule.enableFlags(android.multiuser.Flags.FLAG_DELETE_PRIVATE_SPACE_FROM_RESET); + ResetOptionsDeletePrivateSpaceController spyController = spy(mController); + doReturn(false).when(spyController).isPrivateSpaceEntryPointEnabled(); + + assertThat(spyController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE); } @Test diff --git a/tests/unit/src/com/android/settings/privatespace/HidePrivateSpaceSensitiveNotificationsControllerTest.java b/tests/unit/src/com/android/settings/privatespace/HidePrivateSpaceSensitiveNotificationsControllerTest.java deleted file mode 100644 index 88503a525b6..00000000000 --- a/tests/unit/src/com/android/settings/privatespace/HidePrivateSpaceSensitiveNotificationsControllerTest.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * 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.privatespace; - -import static com.android.settings.core.BasePreferenceController.AVAILABLE; -import static com.android.settings.core.BasePreferenceController.DISABLED_DEPENDENT_SETTING; -import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE; - -import static com.google.common.truth.Truth.assertThat; - -import static org.junit.Assume.assumeTrue; -import static org.mockito.Mockito.spy; - -import android.content.ContentResolver; -import android.content.Context; -import android.platform.test.flag.junit.SetFlagsRule; -import android.provider.Settings; - -import androidx.test.core.app.ApplicationProvider; -import androidx.test.ext.junit.runners.AndroidJUnit4; - -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; - -/** - * Tests for HidePrivateSpaceSensitiveNotificationsController. - * Run as {@code atest SettingsUnitTests:HidePrivateSpaceSensitiveNotificationsControllerTest} - */ -@RunWith(AndroidJUnit4.class) -public class HidePrivateSpaceSensitiveNotificationsControllerTest { - @Rule - public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); - - private Context mContext; - private HidePrivateSpaceSensitiveNotificationsController - mHidePrivateSpaceSensitiveNotificationsController; - @Mock - private ContentResolver mContentResolver; - private int mOriginalDeviceSensitiveNotifValue; - private int mOriginalDeviceNotifValue; - private int mOriginalPsSensitiveNotifValue; - private int mPrivateProfileId; - - @Before - public void setUp() { - mContext = spy(ApplicationProvider.getApplicationContext()); - mContentResolver = mContext.getContentResolver(); - assumeTrue(PrivateSpaceMaintainer.getInstance(mContext).doesPrivateSpaceExist()); - - mSetFlagsRule.enableFlags( - android.multiuser.Flags.FLAG_ENABLE_PS_SENSITIVE_NOTIFICATIONS_TOGGLE); - mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE, - android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); - - mPrivateProfileId = PrivateSpaceMaintainer.getInstance( - mContext).getPrivateProfileHandle().getIdentifier(); - - mOriginalDeviceSensitiveNotifValue = Settings.Secure.getInt(mContentResolver, - Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 1); - mOriginalDeviceNotifValue = Settings.Secure.getInt(mContentResolver, - Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 1); - mOriginalPsSensitiveNotifValue = Settings.Secure.getIntForUser(mContentResolver, - Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0, mPrivateProfileId); - - final String preferenceKey = "private_space_sensitive_notifications"; - mHidePrivateSpaceSensitiveNotificationsController = - new HidePrivateSpaceSensitiveNotificationsController(mContext, preferenceKey); - } - - @After - public void tearDown() { - Settings.Secure.putInt(mContentResolver, - Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, - mOriginalDeviceSensitiveNotifValue - ); - Settings.Secure.putInt(mContext.getContentResolver(), - Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, mOriginalDeviceNotifValue); - Settings.Secure.putIntForUser(mContext.getContentResolver(), - Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, - mOriginalPsSensitiveNotifValue, mPrivateProfileId); - } - - /** - * Tests that the controller is unavailable if lockscreen sensitive notifications are disabled - * on the device. - */ - @Test - public void getAvailabilityStatus_lockScreenPrivateNotificationsOff() { - Settings.Secure.putInt(mContext.getContentResolver(), - Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0); - assertThat(mHidePrivateSpaceSensitiveNotificationsController.getAvailabilityStatus()) - .isEqualTo(DISABLED_DEPENDENT_SETTING); - } - - /** - * Tests that the controller is unavailable if lockscreen notifications are disabled on the - * device. - */ - @Test - public void getAvailabilityStatus_lockScreenNotificationsOff() { - Settings.Secure.putInt(mContext.getContentResolver(), - Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0); - assertThat(mHidePrivateSpaceSensitiveNotificationsController.getAvailabilityStatus()) - .isEqualTo(DISABLED_DEPENDENT_SETTING); - } - - /** - * Tests that the controller is available if lockscreen notifications and lockscreen private - * notifications are enabled on the device. - */ - @Test - public void getAvailabilityStatus_returnAvailable() { - Settings.Secure.putInt(mContext.getContentResolver(), - Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 1); - Settings.Secure.putInt(mContext.getContentResolver(), - Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 1); - assertThat(mHidePrivateSpaceSensitiveNotificationsController.getAvailabilityStatus()) - .isEqualTo(AVAILABLE); - } - - - /** - * Tests that toggle is not available if the flag for this feature and MVP flag are disabled. - */ - @Test - public void getAvailabilityStatus_flagDisabled() { - mSetFlagsRule.disableFlags( - android.multiuser.Flags.FLAG_ENABLE_PS_SENSITIVE_NOTIFICATIONS_TOGGLE); - 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(), - Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 1); - assertThat(mHidePrivateSpaceSensitiveNotificationsController.getAvailabilityStatus()) - .isEqualTo(UNSUPPORTED_ON_DEVICE); - } - - @Test - public void testSetChecked() { - assertThat(mHidePrivateSpaceSensitiveNotificationsController.setChecked(true)).isTrue(); - assertThat(mHidePrivateSpaceSensitiveNotificationsController.isChecked()).isEqualTo(true); - assertThat(mHidePrivateSpaceSensitiveNotificationsController.setChecked(false)).isTrue(); - assertThat(mHidePrivateSpaceSensitiveNotificationsController.isChecked()).isEqualTo(false); - } -} diff --git a/tests/unit/src/com/android/settings/privatespace/PrivateSpaceMaintainerTest.java b/tests/unit/src/com/android/settings/privatespace/PrivateSpaceMaintainerTest.java index 50f67d3c55b..6f3cb75820f 100644 --- a/tests/unit/src/com/android/settings/privatespace/PrivateSpaceMaintainerTest.java +++ b/tests/unit/src/com/android/settings/privatespace/PrivateSpaceMaintainerTest.java @@ -21,16 +21,23 @@ import static android.provider.Settings.Secure.PRIVATE_SPACE_AUTO_LOCK; import static com.android.settings.privatespace.PrivateSpaceMaintainer.HIDE_PRIVATE_SPACE_ENTRY_POINT_DISABLED_VAL; import static com.android.settings.privatespace.PrivateSpaceMaintainer.HIDE_PRIVATE_SPACE_ENTRY_POINT_ENABLED_VAL; +import static com.android.settings.privatespace.PrivateSpaceMaintainer.HIDE_PRIVATE_SPACE_SENSITIVE_NOTIFICATIONS_DISABLED_VAL; import static com.android.settings.privatespace.PrivateSpaceMaintainer.PRIVATE_SPACE_AUTO_LOCK_DEFAULT_VAL; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assume.assumeFalse; +import static org.junit.Assume.assumeTrue; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + import android.app.ActivityManager; import android.app.IActivityManager; import android.content.ContentResolver; import android.content.Context; import android.os.Flags; import android.os.RemoteException; +import android.os.UserManager; import android.platform.test.flag.junit.SetFlagsRule; import android.provider.Settings; @@ -72,6 +79,8 @@ public class PrivateSpaceMaintainerTest { /** Tests that {@link PrivateSpaceMaintainer#deletePrivateSpace()} deletes PS when PS exists. */ @Test public void deletePrivateSpace_psExists_deletesPS() { + mSetFlagsRule.enableFlags( + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); PrivateSpaceMaintainer privateSpaceMaintainer = PrivateSpaceMaintainer.getInstance(mContext); privateSpaceMaintainer.createPrivateSpace(); @@ -88,6 +97,8 @@ public class PrivateSpaceMaintainerTest { */ @Test public void deletePrivateSpace_psDoesNotExist_returnsNoPSError() { + mSetFlagsRule.enableFlags( + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); PrivateSpaceMaintainer privateSpaceMaintainer = PrivateSpaceMaintainer.getInstance(mContext); ErrorDeletingPrivateSpace errorDeletingPrivateSpace = @@ -100,6 +111,8 @@ public class PrivateSpaceMaintainerTest { /** Tests that {@link PrivateSpaceMaintainer#createPrivateSpace()} when PS exists creates PS. */ @Test public void createPrivateSpace_psDoesNotExist_createsPS() { + mSetFlagsRule.enableFlags( + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); PrivateSpaceMaintainer privateSpaceMaintainer = PrivateSpaceMaintainer.getInstance(mContext); privateSpaceMaintainer.deletePrivateSpace(); @@ -113,6 +126,8 @@ public class PrivateSpaceMaintainerTest { */ @Test public void createPrivateSpace_psExists_returnsFalse() { + mSetFlagsRule.enableFlags( + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); PrivateSpaceMaintainer privateSpaceMaintainer = PrivateSpaceMaintainer.getInstance(mContext); privateSpaceMaintainer.deletePrivateSpace(); @@ -127,6 +142,8 @@ public class PrivateSpaceMaintainerTest { */ @Test public void createPrivateSpace_psDoesNotExist_resetsHidePSSettings() { + mSetFlagsRule.enableFlags( + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); PrivateSpaceMaintainer privateSpaceMaintainer = PrivateSpaceMaintainer.getInstance(mContext); Settings.Secure.putInt( @@ -156,7 +173,7 @@ public class PrivateSpaceMaintainerTest { privateSpaceMaintainer.createPrivateSpace(); assertThat(privateSpaceMaintainer.doesPrivateSpaceExist()).isTrue(); assertThat(getPsSensitiveNotificationsValue(privateSpaceMaintainer)) - .isEqualTo(HidePrivateSpaceSensitiveNotificationsController.DISABLED); + .isEqualTo(HIDE_PRIVATE_SPACE_SENSITIVE_NOTIFICATIONS_DISABLED_VAL); } /** @@ -165,6 +182,8 @@ public class PrivateSpaceMaintainerTest { */ @Test public void createPrivateSpace_psExists_doesNotResetHidePSSettings() { + mSetFlagsRule.enableFlags( + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); PrivateSpaceMaintainer privateSpaceMaintainer = PrivateSpaceMaintainer.getInstance(mContext); privateSpaceMaintainer.createPrivateSpace(); @@ -184,6 +203,8 @@ public class PrivateSpaceMaintainerTest { */ @Test public void lockPrivateSpace_psExistsAndPrivateProfileRunning_locksCreatedPrivateSpace() { + mSetFlagsRule.enableFlags( + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); PrivateSpaceMaintainer privateSpaceMaintainer = PrivateSpaceMaintainer.getInstance(mContext); privateSpaceMaintainer.createPrivateSpace(); @@ -200,6 +221,8 @@ public class PrivateSpaceMaintainerTest { */ @Test public void lockPrivateSpace_psExistsAndPrivateProfileNotRunning_returnsFalse() { + mSetFlagsRule.enableFlags( + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); PrivateSpaceMaintainer privateSpaceMaintainer = PrivateSpaceMaintainer.getInstance(mContext); privateSpaceMaintainer.createPrivateSpace(); @@ -220,6 +243,8 @@ public class PrivateSpaceMaintainerTest { */ @Test public void lockPrivateSpace_psDoesNotExist_returnsFalse() { + mSetFlagsRule.enableFlags( + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); PrivateSpaceMaintainer privateSpaceMaintainer = PrivateSpaceMaintainer.getInstance(mContext); assertThat(privateSpaceMaintainer.doesPrivateSpaceExist()).isFalse(); @@ -232,6 +257,8 @@ public class PrivateSpaceMaintainerTest { */ @Test public void createPrivateSpace_psDoesNotExist_setsUserSetupComplete() { + mSetFlagsRule.enableFlags( + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); PrivateSpaceMaintainer privateSpaceMaintainer = PrivateSpaceMaintainer.getInstance(mContext); privateSpaceMaintainer.createPrivateSpace(); @@ -244,6 +271,8 @@ public class PrivateSpaceMaintainerTest { */ @Test public void createPrivateSpace_pSExists_doesNotChangeUserSetupSetting() { + mSetFlagsRule.enableFlags( + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); PrivateSpaceMaintainer privateSpaceMaintainer = PrivateSpaceMaintainer.getInstance(mContext); privateSpaceMaintainer.createPrivateSpace(); @@ -300,6 +329,61 @@ public class PrivateSpaceMaintainerTest { .isEqualTo(privateSpaceAutLockValue); } + @Test + public void isPrivateSpaceEntryPointEnabled_psExistCanAddProfileTrue_returnsTrue() { + mSetFlagsRule.enableFlags( + Flags.FLAG_ALLOW_PRIVATE_PROFILE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); + assumeTrue(mContext.getSystemService(UserManager.class).canAddPrivateProfile()); + PrivateSpaceMaintainer privateSpaceMaintainer = + PrivateSpaceMaintainer.getInstance(mContext); + privateSpaceMaintainer.createPrivateSpace(); + assertThat(privateSpaceMaintainer.doesPrivateSpaceExist()).isTrue(); + + assertThat(privateSpaceMaintainer.isPrivateSpaceEntryPointEnabled()).isTrue(); + } + + @Test + public void isPrivateSpaceEntryPointEnabled_psNotExistsCanAddProfileTrue_returnsTrue() { + mSetFlagsRule.enableFlags( + Flags.FLAG_ALLOW_PRIVATE_PROFILE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); + assumeTrue(mContext.getSystemService(UserManager.class).canAddPrivateProfile()); + PrivateSpaceMaintainer privateSpaceMaintainer = + PrivateSpaceMaintainer.getInstance(mContext); + privateSpaceMaintainer.deletePrivateSpace(); + assertThat(privateSpaceMaintainer.doesPrivateSpaceExist()).isFalse(); + + assertThat(privateSpaceMaintainer.isPrivateSpaceEntryPointEnabled()).isTrue(); + } + + @Test + public void isPrivateSpaceEntryPointEnabled_psExistsCanAddProfileFalse_returnsTrue() { + mSetFlagsRule.enableFlags( + Flags.FLAG_ALLOW_PRIVATE_PROFILE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); + assumeFalse(mContext.getSystemService(UserManager.class).canAddPrivateProfile()); + PrivateSpaceMaintainer privateSpaceMaintainer = + spy(PrivateSpaceMaintainer.getInstance(mContext)); + when(privateSpaceMaintainer.doesPrivateSpaceExist()).thenReturn(true); + + assertThat(privateSpaceMaintainer.isPrivateSpaceEntryPointEnabled()).isTrue(); + } + + @Test + public void isPrivateSpaceEntryPointEnabled_psNotExistsCanAddProfileFalse_returnsFalse() { + mSetFlagsRule.enableFlags( + Flags.FLAG_ALLOW_PRIVATE_PROFILE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); + assumeFalse(mContext.getSystemService(UserManager.class).canAddPrivateProfile()); + PrivateSpaceMaintainer privateSpaceMaintainer = + PrivateSpaceMaintainer.getInstance(mContext); + privateSpaceMaintainer.deletePrivateSpace(); + assertThat(privateSpaceMaintainer.doesPrivateSpaceExist()).isFalse(); + + assertThat(privateSpaceMaintainer.isPrivateSpaceEntryPointEnabled()).isFalse(); + } + private int getSecureUserSetupComplete() { PrivateSpaceMaintainer privateSpaceMaintainer = PrivateSpaceMaintainer.getInstance(mContext); @@ -313,7 +397,7 @@ public class PrivateSpaceMaintainerTest { private int getPsSensitiveNotificationsValue(PrivateSpaceMaintainer privateSpaceMaintainer) { return Settings.Secure.getIntForUser(mContentResolver, LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, - HidePrivateSpaceSensitiveNotificationsController.ENABLED, + /* enabled */ 1, privateSpaceMaintainer.getPrivateProfileHandle().getIdentifier()); } }