From e99d19cd85fed41e99ff49befcee54d521801e2c Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Wed, 31 Jan 2024 00:47:49 -0800 Subject: [PATCH 1/4] Import translations. DO NOT MERGE ANYWHERE Auto-generated-cl: translation import Change-Id: Ia6925d0bfc9475932b9a441d7619bc888836583c --- res/values-eu/arrays.xml | 4 ++-- res/values-ja/arrays.xml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/res/values-eu/arrays.xml b/res/values-eu/arrays.xml index 700229c4c2b..7b9a208d206 100644 --- a/res/values-eu/arrays.xml +++ b/res/values-eu/arrays.xml @@ -221,7 +221,7 @@ "imitate kokapena" "irakurri memoria" "idatzi memorian" - "aktibatu pantaila" + "piztu pantaila" "lortu kontuak" "exekutatu atzeko planoan" "erabilerraztasun-eginbideen bolumena" @@ -288,7 +288,7 @@ "Imitatu kokapena" "Irakurri memoria" "Idatzi memorian" - "Aktibatu pantaila" + "Piztu pantaila" "Lortu kontuak" "Abiarazi atzeko planoan" "Erabilerraztasun-eginbideen bolumena" diff --git a/res/values-ja/arrays.xml b/res/values-ja/arrays.xml index d3cadf8cab0..0553b20470e 100644 --- a/res/values-ja/arrays.xml +++ b/res/values-ja/arrays.xml @@ -306,7 +306,7 @@ "デフォルト" "Sans Serif" - "Sans Serif Condensed" + "Sans Serif コンデンス" "Sans Serif 固定幅" "Serif" "Serif 固定幅" From e1a2a0f164bdc388ead6359454a8f2b466fdf8d0 Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Wed, 31 Jan 2024 00:51:05 -0800 Subject: [PATCH 2/4] Import translations. DO NOT MERGE ANYWHERE Auto-generated-cl: translation import Change-Id: If98d3ff31e422f5e52d27f3faafb57402c3a7427 --- res/values-de/strings.xml | 4 ++-- res/values-fa/strings.xml | 6 +++--- res/values-gl/strings.xml | 6 +++--- res/values-hi/strings.xml | 2 +- res/values-in/strings.xml | 2 +- res/values-my/strings.xml | 2 +- res/values-pt-rPT/strings.xml | 8 ++++---- res/values-te/strings.xml | 2 +- 8 files changed, 16 insertions(+), 16 deletions(-) diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml index 6917223b347..981a3c48849 100644 --- a/res/values-de/strings.xml +++ b/res/values-de/strings.xml @@ -501,10 +501,10 @@ "Verschlüsselung" "Verschlüsselt" "Displaysperre einrichten" - "Für zusätzliche Sicherheit lässt sich eine PIN, ein Muster oder ein Passwort einrichten." + "Für mehr Sicherheit kannst du eine PIN, ein Muster oder ein Passwort einrichten." "Displaysperre einrichten" "Displaysperre einrichten" - "Für zusätzliche Sicherheit lässt sich eine PIN, ein Muster oder ein Passwort einrichten." + "Für mehr Sicherheit kannst du eine PIN, ein Muster oder ein Passwort einrichten." "Smartphone schützen" "Fingerabdruck zum Entsperren hinzufügen" "Displaysperre wählen" diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml index b707c2ecec6..21cb3440188 100644 --- a/res/values-fa/strings.xml +++ b/res/values-fa/strings.xml @@ -1733,15 +1733,15 @@ "با سه انگشت تند به‌پایین بکشید" "جابه‌جایی بین برنامه‌ها" "با چهار انگشت تند به‌چپ یا راست بکشید" - "کلیدهای تغییردهنده" + "کلیدهای توصیف‌گر" "تغییر رفتار کلیدها" "بازنشانی همه" "پیش‌فرض" - "مطمئنید می‌خواهید همه کلیدهای تغییردهنده را به تنظیم پیش‌فرض بازنشانی کنید؟" + "مطمئنید می‌خواهید همه کلیدهای توصیف‌گر را به تنظیم پیش‌فرض بازنشانی کنید؟" "تمام" "لغو" "بازنشانی" - "کلید تغییردهنده را انتخاب کنید" + "کلید توصیف‌گر را انتخاب کنید" "کلید جدیدی برای %1$s انتخاب کنید:" "پیش‌فرض" "گفتار" diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml index 64e43eb0e14..f6dcab9e0dc 100644 --- a/res/values-gl/strings.xml +++ b/res/values-gl/strings.xml @@ -201,8 +201,8 @@ "Non se poden quitar todos os idiomas" "Conserva polo menos un idioma preferido" "Non dispoñible como idioma do sistema" - "Mover cara a arriba" - "Mover cara a abaixo" + "Mover cara arriba" + "Mover cara abaixo" "Situar arriba" "Situar abaixo" "Quitar idioma" @@ -1007,7 +1007,7 @@ "Desactivado" "Balance de brancos da pantalla" - "Seguir usando aplicacións co dispositivo pregado" + "Usar apps co dispositivo pregado" "Pantalla fluída" "Incrementa automaticamente a frecuencia de actualización de 60 a %1$s Hz en determinados tipos de contido. Aumenta o uso da batería." "Forzar taxa de actualización máxima" diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml index 7588cbe5548..6308c1981f0 100644 --- a/res/values-hi/strings.xml +++ b/res/values-hi/strings.xml @@ -410,7 +410,7 @@ "सेट अप न करें" "रद्द करें" "सेंसर को छुएं" - "पावर बटन को बिना दबाए हाथ से छुएं" + "पावर बटन को दबाने के बजाय, इसे बस उंगली से छुएं" "फ़िंगरप्रिंट सेट अप करने का तरीका" "यह आपके फ़ोन के पीछे दिया गया है. अपने अंगूठे के पास की उंगली का उपयोग करें." "फ़िंगरप्रिंट सेंसर आपकी स्क्रीन पर मौजूद है. आपको अगली स्क्रीन पर अपना फ़िंगरप्रिंट कैप्चर करने का विकल्प मिलेगा." diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml index 2f82ebd86c6..712a8daada6 100644 --- a/res/values-in/strings.xml +++ b/res/values-in/strings.xml @@ -2401,7 +2401,7 @@ "Pengenalan ucapan di perangkat" "Mesin yang dipilih" "Setelan mesin" - "Kecepatan & tinggi nada ucapan" + "Kecepatan bicara & tinggi nada" "Mesin" "Suara" "Bahasa Lisan" diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml index c80500645aa..9ea25be565b 100644 --- a/res/values-my/strings.xml +++ b/res/values-my/strings.xml @@ -1007,7 +1007,7 @@ "ပိတ်" "ဖန်သားပြင် အဖြူ ချိန်ညှိခြင်း" - "ခေါက်ထားချိန် အက်ပ်များကို ဆက်သုံးရန်" + "ခေါက်ထားချိန် အက်ပ်ဆက်သုံးရန်" "Smooth Display" "အကြောင်းအရာအချို့အတွက် ပြန်လည်စတင်နှုန်းကို ၆၀ မှ %1$s Hz သို့ အလိုအလျောက် တိုးပေးသည်။ ဘက်ထရီ အသုံးပြုမှု များလာမည်။" "အမြင့်ဆုံး ပြန်လည် စတင်နှုန်းသို့ တွန်းအားပေးရန်" diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml index 193e2365ee5..1ca5d6089e8 100644 --- a/res/values-pt-rPT/strings.xml +++ b/res/values-pt-rPT/strings.xml @@ -3598,7 +3598,7 @@ "Armazenamento de apps" "Acesso de utilização" "Permitir acesso de utilização" - "Tempo de utilização" + "Tempo ao ecrã" "O acesso de utilização permite a uma aplicação monitorizar que outras aplicações está a utilizar e com que frequência, bem como o operador e as definições de idioma, entre outros detalhes." "Memória" "Sempre em execução (%s)" @@ -3952,7 +3952,7 @@ "Modo de navegação" "Navegação com 2 botões" - "Para mudar de app, deslize rapidamente para cima no botão página inicial. Para ver todas as apps, volte a deslizar rapidamente para cima. Para retroceder, toque no botão Anterior." + "Para mudar de app, deslize rapidamente para cima no botão do ecrã principal. Para ver todas as apps, volte a deslizar rapidamente para cima. Para retroceder, toque no botão Anterior." "Segurança e emergência" "Urgência SOS, informações médicas, alertas" "Navegação por gestos" @@ -3964,7 +3964,7 @@ "Deslizar rapidamente para invocar assistente" "Deslize rapidamente para cima a partir de um canto inferior para invocar a app de assistente digital." "Prima sem soltar Página inicial para chamar o Assistente" - "Prima sem soltar o botão página inicial para invocar a app de assistente digital." + "Prima sem soltar o botão do ecrã principal para invocar a app de assistente digital." "Baixa" "Elevada" "Extremidade esquerda" @@ -3974,7 +3974,7 @@ "Sensibilidade da navegação por gestos" "Navegação com botões" "navegação por gestos, sensibilidade do botão anterior, gesto para voltar" - "navegação, botão página inicial" + "navegação, botão do ecrã principal" "Modo para uma mão" "Usar o modo para uma mão" "Atalho do modo para uma mão" diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml index 807e15be888..01d98381dbb 100644 --- a/res/values-te/strings.xml +++ b/res/values-te/strings.xml @@ -1007,7 +1007,7 @@ "ఆఫ్" "తెలుపు సమతుల్యతను ప్రదర్శించండి" - "ఫోల్డ్‌లో ఉన్న యాప్‌లను ఉపయోగించడం కొనసాగించండి" + "ఫోల్డ్ చేసినప్పుడు యాప్స్ వాడటం కొనసాగించండి" "స్మూత్ డిస్‌ప్లే" "కొంత కంటెంట్ కోసం రిఫ్రెష్ రేటును ఆటోమేటిక్‌గా 60 నుండి %1$s Hz వరకు పెంచుతుంది. బ్యాటరీ వినియోగం పెరుగుతుంది." "ఫోర్స్ పీక్ రిఫ్రెష్ రేటు" From 4504f0ace4d6449e4436aad5fd3705555d9d829d Mon Sep 17 00:00:00 2001 From: Ahmad Khalil Date: Wed, 31 Jan 2024 10:45:55 +0000 Subject: [PATCH 3/4] Fix notification vibration demos in settings While in zen mode, notification vibrations are ignored. These vibrations will also be ignored when attempting to demo the vibration intensity in settings. Adding FLAG_BYPASS_INTERRUPTION_POLICY to the attributes of the vibration preview, to allow it to bypass the interruption policy and demo the vibration intensity as expected. Fix: 301319836 Test: N/A Change-Id: I240a896ff8e9516388a0238882db07f9680a184a --- .../accessibility/VibrationPreferenceConfig.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/com/android/settings/accessibility/VibrationPreferenceConfig.java b/src/com/android/settings/accessibility/VibrationPreferenceConfig.java index c25c38e5a6d..a3048622fb0 100644 --- a/src/com/android/settings/accessibility/VibrationPreferenceConfig.java +++ b/src/com/android/settings/accessibility/VibrationPreferenceConfig.java @@ -150,9 +150,13 @@ public abstract class VibrationPreferenceConfig { @VibrationAttributes.Usage int vibrationUsage) { return new VibrationAttributes.Builder() .setUsage(vibrationUsage) - // Enforce fresh settings to be applied for the preview vibration, as they - // are played immediately after the new user values are set. - .setFlags(VibrationAttributes.FLAG_INVALIDATE_SETTINGS_CACHE) + .setFlags( + // Enforce fresh settings to be applied for the preview vibration, as they + // are played immediately after the new user values are set. + VibrationAttributes.FLAG_INVALIDATE_SETTINGS_CACHE + // Bypass user settings to allow vibration previews to be played while in + // limited interruptions' mode, e.g. zen mode. + | VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY) .build(); } From e1a2c82db37551db768274e04d5f2592f64ff9f0 Mon Sep 17 00:00:00 2001 From: josephpv Date: Thu, 21 Dec 2023 18:57:49 +0000 Subject: [PATCH 4/4] Add Private space Delete settings page inside PS settings page Contains implementation of settings page for Delete private space controller inside private space settings page. - On selecting to delete private space displays list of account signed in to private profile and deletes the private space after authentication. - Shows a toast message after private space is deleted - Adds dependency for setupdesgin loading layout to show a loading screen while deletion of private space is in progress. Recording Link : b/318383729 go/ss/4Aq3rmbSGHMHesK.png Bug: 318383729 Test: atest DeletePrivateSpaceControllerTest Change-Id: Ia1730915e2469b47823c507f9ef6cd8f63c99baf --- Android.bp | 1 + AndroidManifest.xml | 5 + res/layout/private_space_confirm_deletion.xml | 30 +++ res/layout/private_space_delete.xml | 68 +++++++ res/navigation/private_space_delete_nav.xml | 31 ++++ res/values/strings.xml | 16 +- res/xml/private_space_settings.xml | 2 +- .../core/gateway/SettingsGateway.java | 4 + .../DeletePrivateSpaceController.java | 90 --------- .../privatespace/PrivateSpaceMaintainer.java | 3 +- .../delete/DeletePrivateSpaceController.java | 53 ++++++ .../delete/PrivateSpaceDeleteActivity.java | 50 +++++ .../delete/PrivateSpaceDeleteFragment.java | 172 ++++++++++++++++++ .../PrivateSpaceDeletionProgressFragment.java | 143 +++++++++++++++ .../DeletePrivateSpaceControllerTest.java | 108 ----------- .../DeletePrivateSpaceControllerTest.java | 74 ++++++++ .../PrivateSpaceDeleteFragmentTest.java | 46 +++++ ...vateSpaceDeletionProgressFragmentTest.java | 132 ++++++++++++++ 18 files changed, 826 insertions(+), 202 deletions(-) create mode 100644 res/layout/private_space_confirm_deletion.xml create mode 100644 res/layout/private_space_delete.xml create mode 100644 res/navigation/private_space_delete_nav.xml delete mode 100644 src/com/android/settings/privatespace/DeletePrivateSpaceController.java create mode 100644 src/com/android/settings/privatespace/delete/DeletePrivateSpaceController.java create mode 100644 src/com/android/settings/privatespace/delete/PrivateSpaceDeleteActivity.java create mode 100644 src/com/android/settings/privatespace/delete/PrivateSpaceDeleteFragment.java create mode 100644 src/com/android/settings/privatespace/delete/PrivateSpaceDeletionProgressFragment.java delete mode 100644 tests/unit/src/com/android/settings/privatespace/DeletePrivateSpaceControllerTest.java create mode 100644 tests/unit/src/com/android/settings/privatespace/delete/DeletePrivateSpaceControllerTest.java create mode 100644 tests/unit/src/com/android/settings/privatespace/delete/PrivateSpaceDeleteFragmentTest.java create mode 100644 tests/unit/src/com/android/settings/privatespace/delete/PrivateSpaceDeletionProgressFragmentTest.java diff --git a/Android.bp b/Android.bp index eef73a43dd3..737c16cc3f6 100644 --- a/Android.bp +++ b/Android.bp @@ -109,6 +109,7 @@ android_library { "statslog-settings", "androidx.test.rules", "telephony_flags_core_java_lib", + "setupdesign-lottie-loading-layout", ], plugins: ["androidx.room_room-compiler-plugin"], diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 195c44ecd23..c8f35ae561c 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -5070,6 +5070,11 @@ + + + + + + + \ No newline at end of file diff --git a/res/layout/private_space_delete.xml b/res/layout/private_space_delete.xml new file mode 100644 index 00000000000..9fc36157a3b --- /dev/null +++ b/res/layout/private_space_delete.xml @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/res/navigation/private_space_delete_nav.xml b/res/navigation/private_space_delete_nav.xml new file mode 100644 index 00000000000..b8850b7f348 --- /dev/null +++ b/res/navigation/private_space_delete_nav.xml @@ -0,0 +1,31 @@ + + + + + + + + diff --git a/res/values/strings.xml b/res/values/strings.xml index b760f68e872..78900bc1584 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -1280,8 +1280,20 @@ On System - - Delete Private Space + + Delete private space + + Delete private space? + + Your private space will be removed from your device. All private apps and data will be deleted. You can’t undo this action. + + The following accounts will be removed from your private space: + + Delete + + Deleting private space\u2026 + + This will take a few moments Private Space successfully deleted diff --git a/res/xml/private_space_settings.xml b/res/xml/private_space_settings.xml index 244c792c7e5..a3dfbf22906 100644 --- a/res/xml/private_space_settings.xml +++ b/res/xml/private_space_settings.xml @@ -65,7 +65,7 @@ diff --git a/src/com/android/settings/core/gateway/SettingsGateway.java b/src/com/android/settings/core/gateway/SettingsGateway.java index 8fee052b19f..b4de8ccce95 100644 --- a/src/com/android/settings/core/gateway/SettingsGateway.java +++ b/src/com/android/settings/core/gateway/SettingsGateway.java @@ -169,6 +169,8 @@ import com.android.settings.print.PrintJobSettingsFragment; import com.android.settings.print.PrintSettingsFragment; import com.android.settings.privacy.PrivacyControlsFragment; import com.android.settings.privacy.PrivacyDashboardFragment; +import com.android.settings.privatespace.delete.PrivateSpaceDeleteFragment; +import com.android.settings.privatespace.delete.PrivateSpaceDeletionProgressFragment; import com.android.settings.privatespace.onelock.PrivateSpaceBiometricSettings; import com.android.settings.regionalpreferences.RegionalPreferencesEntriesFragment; import com.android.settings.safetycenter.MoreSecurityPrivacyFragment; @@ -271,6 +273,8 @@ public class SettingsGateway { CombinedBiometricSettings.class.getName(), CombinedBiometricProfileSettings.class.getName(), PrivateSpaceBiometricSettings.class.getName(), + PrivateSpaceDeleteFragment.class.getName(), + PrivateSpaceDeletionProgressFragment.class.getName(), SwipeToNotificationSettings.class.getName(), DoubleTapPowerSettings.class.getName(), DoubleTapScreenSettings.class.getName(), diff --git a/src/com/android/settings/privatespace/DeletePrivateSpaceController.java b/src/com/android/settings/privatespace/DeletePrivateSpaceController.java deleted file mode 100644 index 98bf82705be..00000000000 --- a/src/com/android/settings/privatespace/DeletePrivateSpaceController.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.privatespace; - -import static com.android.settings.privatespace.PrivateSpaceMaintainer.ErrorDeletingPrivateSpace.DELETE_PS_ERROR_INTERNAL; -import static com.android.settings.privatespace.PrivateSpaceMaintainer.ErrorDeletingPrivateSpace.DELETE_PS_ERROR_NONE; -import static com.android.settings.privatespace.PrivateSpaceMaintainer.ErrorDeletingPrivateSpace.DELETE_PS_ERROR_NO_PRIVATE_SPACE; - -import android.content.Context; -import android.text.TextUtils; -import android.util.Log; -import android.widget.Toast; - -import androidx.preference.Preference; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.settings.R; -import com.android.settings.core.BasePreferenceController; - -/** Controller to delete the private space from the PS Settings page */ -public class DeletePrivateSpaceController extends BasePreferenceController { - private static final String TAG = "DeletePrivateSpaceController"; - private final PrivateSpaceMaintainer mPrivateSpaceMaintainer; - - static class Injector { - PrivateSpaceMaintainer injectPrivateSpaceMaintainer(Context context) { - return PrivateSpaceMaintainer.getInstance(context); - } - } - - public DeletePrivateSpaceController(Context context, String preferenceKey) { - this(context, preferenceKey, new Injector()); - } - - DeletePrivateSpaceController(Context context, String preferenceKey, Injector injector) { - super(context, preferenceKey); - mPrivateSpaceMaintainer = injector.injectPrivateSpaceMaintainer(context); - } - - @Override - public int getAvailabilityStatus() { - return android.os.Flags.allowPrivateProfile() ? AVAILABLE : UNSUPPORTED_ON_DEVICE; - } - - @Override - public boolean handlePreferenceTreeClick(Preference preference) { - if (!TextUtils.equals(preference.getKey(), getPreferenceKey())) { - return false; - } - - PrivateSpaceMaintainer.ErrorDeletingPrivateSpace error = - mPrivateSpaceMaintainer.deletePrivateSpace(); - if (error == DELETE_PS_ERROR_NONE) { - showSuccessfulDeletionToast(); - } else if (error == DELETE_PS_ERROR_INTERNAL) { - showDeletionInternalErrorToast(); - } else if (error == DELETE_PS_ERROR_NO_PRIVATE_SPACE) { - // Ideally this should never happen as PS Settings is not available when there's no - // Private Profile. - Log.e(TAG, "Unexpected attempt to delete non-existent PS"); - } - return super.handlePreferenceTreeClick(preference); - } - - /** Shows a toast saying that the private space was deleted */ - @VisibleForTesting - public void showSuccessfulDeletionToast() { - Toast.makeText(mContext, R.string.private_space_deleted, Toast.LENGTH_SHORT).show(); - } - - /** Shows a toast saying that the private space could not be deleted */ - @VisibleForTesting - public void showDeletionInternalErrorToast() { - Toast.makeText(mContext, R.string.private_space_delete_failed, Toast.LENGTH_SHORT).show(); - } -} diff --git a/src/com/android/settings/privatespace/PrivateSpaceMaintainer.java b/src/com/android/settings/privatespace/PrivateSpaceMaintainer.java index 8d6831406f9..a2831478a8b 100644 --- a/src/com/android/settings/privatespace/PrivateSpaceMaintainer.java +++ b/src/com/android/settings/privatespace/PrivateSpaceMaintainer.java @@ -75,7 +75,8 @@ public class PrivateSpaceMaintainer { * *

This method should be used by the Private Space Setup Flow ONLY. */ - final synchronized boolean createPrivateSpace() { + @VisibleForTesting + public final synchronized boolean createPrivateSpace() { if (!Flags.allowPrivateProfile()) { return false; } diff --git a/src/com/android/settings/privatespace/delete/DeletePrivateSpaceController.java b/src/com/android/settings/privatespace/delete/DeletePrivateSpaceController.java new file mode 100644 index 00000000000..af4535ec43a --- /dev/null +++ b/src/com/android/settings/privatespace/delete/DeletePrivateSpaceController.java @@ -0,0 +1,53 @@ +/* + * 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.privatespace.delete; + +import android.content.Context; +import android.content.Intent; + +import androidx.annotation.NonNull; +import androidx.preference.Preference; + +import com.android.settings.core.BasePreferenceController; + +/** Controller to delete the private space from the PS Settings page */ +public class DeletePrivateSpaceController extends BasePreferenceController { + private static final String TAG = "PrivateSpaceDeleteCtrl"; + + public DeletePrivateSpaceController(@NonNull Context context, @NonNull String preferenceKey) { + super(context, preferenceKey); + } + + @Override + public int getAvailabilityStatus() { + return android.os.Flags.allowPrivateProfile() ? AVAILABLE : UNSUPPORTED_ON_DEVICE; + } + + @Override + public boolean handlePreferenceTreeClick(@NonNull Preference preference) { + if (mPreferenceKey.equals(preference.getKey())) { + startPrivateSpaceDeleteActivity(); + return true; + } + return false; + } + + private void startPrivateSpaceDeleteActivity() { + final Intent intent = new Intent(mContext, PrivateSpaceDeleteActivity.class); + mContext.startActivity(intent); + } +} diff --git a/src/com/android/settings/privatespace/delete/PrivateSpaceDeleteActivity.java b/src/com/android/settings/privatespace/delete/PrivateSpaceDeleteActivity.java new file mode 100644 index 00000000000..a4109b868bc --- /dev/null +++ b/src/com/android/settings/privatespace/delete/PrivateSpaceDeleteActivity.java @@ -0,0 +1,50 @@ +/* + * 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.delete; + +import android.app.settings.SettingsEnums; +import android.os.Bundle; + +import androidx.navigation.fragment.NavHostFragment; + +import com.android.settings.R; +import com.android.settings.SetupWizardUtils; +import com.android.settings.core.InstrumentedActivity; + +import com.google.android.setupdesign.util.ThemeHelper; + +public class PrivateSpaceDeleteActivity extends InstrumentedActivity { + @Override + public int getMetricsCategory() { + return SettingsEnums.PRIVATE_SPACE_SETTINGS; + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + if (!android.os.Flags.allowPrivateProfile()) { + return; + } + setTheme(SetupWizardUtils.getTheme(this, getIntent())); + ThemeHelper.trySetDynamicColor(this); + super.onCreate(savedInstanceState); + setContentView(R.layout.privatespace_setup_root); + NavHostFragment navHostFragment = + (NavHostFragment) + getSupportFragmentManager().findFragmentById(R.id.ps_nav_host_fragment); + navHostFragment.getNavController().setGraph(R.navigation.private_space_delete_nav); + } +} diff --git a/src/com/android/settings/privatespace/delete/PrivateSpaceDeleteFragment.java b/src/com/android/settings/privatespace/delete/PrivateSpaceDeleteFragment.java new file mode 100644 index 00000000000..7dd3a5b0102 --- /dev/null +++ b/src/com/android/settings/privatespace/delete/PrivateSpaceDeleteFragment.java @@ -0,0 +1,172 @@ +/* + * 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.privatespace.delete; + +import android.accounts.Account; +import android.accounts.AccountManager; +import android.app.Activity; +import android.app.settings.SettingsEnums; +import android.content.Context; +import android.content.Intent; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.os.UserHandle; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +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.android.settings.password.ChooseLockSettingsHelper; +import com.android.settings.privatespace.PrivateSpaceMaintainer; +import com.android.settingslib.accounts.AuthenticatorHelper; + +import com.google.android.setupcompat.template.FooterBarMixin; +import com.google.android.setupcompat.template.FooterButton; +import com.google.android.setupdesign.GlifLayout; + +/** Fragment to delete private space that lists the accounts logged in to the private profile. */ +public class PrivateSpaceDeleteFragment extends InstrumentedFragment { + private static final String TAG = "PrivateSpaceDeleteFrag"; + private View mContentView; + private static final int CREDENTIAL_CONFIRM_REQUEST = 1; + @Nullable private UserHandle mPrivateUserHandle; + + @Override + public void onCreate(@Nullable Bundle icicle) { + if (android.os.Flags.allowPrivateProfile()) { + super.onCreate(icicle); + } + } + + @Override + public void onStart() { + super.onStart(); + if (PrivateSpaceMaintainer.getInstance(getContext()).isPrivateSpaceLocked()) { + getActivity().finish(); + } + } + + @Override + public int getMetricsCategory() { + return SettingsEnums.PRIVATE_SPACE_SETTINGS; + } + + private View.OnClickListener startAuthenticationForDelete() { + return v -> { + final ChooseLockSettingsHelper.Builder builder = + new ChooseLockSettingsHelper.Builder(getActivity(), this); + if (mPrivateUserHandle != null) { + builder.setRequestCode(CREDENTIAL_CONFIRM_REQUEST) + .setUserId(mPrivateUserHandle.getIdentifier()) + .show(); + } else { + Log.e(TAG, "Private space user handle cannot be null"); + getActivity().finish(); + } + }; + } + + @NonNull + @Override + public View onCreateView( + @NonNull LayoutInflater inflater, + @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + mPrivateUserHandle = + PrivateSpaceMaintainer.getInstance(getContext()).getPrivateProfileHandle(); + if (mPrivateUserHandle == null) { + Log.e(TAG, "Private space user handle cannot be null"); + getActivity().finish(); + } + mContentView = inflater.inflate(R.layout.private_space_delete, container, false); + final GlifLayout layout = mContentView.findViewById(R.id.private_space_delete_layout); + final FooterBarMixin mixin = layout.getMixin(FooterBarMixin.class); + final Activity activity = getActivity(); + mixin.setPrimaryButton( + new FooterButton.Builder(activity) + .setText(R.string.private_space_delete_button_label) + .setListener(startAuthenticationForDelete()) + .setButtonType(FooterButton.ButtonType.OTHER) + .setTheme(com.google.android.setupdesign.R.style.SudGlifButton_Primary) + .build()); + mixin.setSecondaryButton( + new FooterButton.Builder(activity) + .setText(android.R.string.cancel) + .setListener(view -> activity.onBackPressed()) + .setButtonType(FooterButton.ButtonType.CANCEL) + .setTheme(com.google.android.setupdesign.R.style.SudGlifButton_Secondary) + .build()); + + loadPrivateProfileAccountList(); + return mContentView; + } + + private void loadPrivateProfileAccountList() { + View accountsLabel = mContentView.findViewById(R.id.accounts_label); + LinearLayout contents = (LinearLayout) mContentView.findViewById(R.id.accounts); + contents.removeAllViews(); + + Context context = getActivity(); + + AccountManager accountManager = AccountManager.get(context); + + LayoutInflater inflater = context.getSystemService(LayoutInflater.class); + + final AuthenticatorHelper helper = + new AuthenticatorHelper(context, mPrivateUserHandle, null); + final String[] accountTypes = helper.getEnabledAccountTypes(); + + for (String type : accountTypes) { + final String accountType = type; + final Account[] accounts = + accountManager.getAccountsByTypeAsUser(accountType, mPrivateUserHandle); + Drawable icon = helper.getDrawableForType(getContext(), accountType); + if (icon == null) { + icon = context.getPackageManager().getDefaultActivityIcon(); + } + for (Account account : accounts) { + View child = inflater.inflate(R.layout.main_clear_account, contents, false); + child.findViewById(android.R.id.icon).setImageDrawable(icon); + child.findViewById(android.R.id.title).setText(account.name); + contents.addView(child); + } + } + + if (contents.getChildCount() > 0) { + accountsLabel.setVisibility(View.VISIBLE); + contents.setVisibility(View.VISIBLE); + } + } + + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (requestCode == CREDENTIAL_CONFIRM_REQUEST && resultCode == Activity.RESULT_OK) { + NavHostFragment.findNavController(PrivateSpaceDeleteFragment.this) + .navigate(R.id.action_authenticate_delete); + } + } +} diff --git a/src/com/android/settings/privatespace/delete/PrivateSpaceDeletionProgressFragment.java b/src/com/android/settings/privatespace/delete/PrivateSpaceDeletionProgressFragment.java new file mode 100644 index 00000000000..3a166413565 --- /dev/null +++ b/src/com/android/settings/privatespace/delete/PrivateSpaceDeletionProgressFragment.java @@ -0,0 +1,143 @@ +/* + * 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.delete; + +import static com.android.settings.privatespace.PrivateSpaceMaintainer.ErrorDeletingPrivateSpace.DELETE_PS_ERROR_INTERNAL; +import static com.android.settings.privatespace.PrivateSpaceMaintainer.ErrorDeletingPrivateSpace.DELETE_PS_ERROR_NONE; + +import android.app.settings.SettingsEnums; +import android.content.Context; +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 android.widget.Toast; + +import androidx.activity.OnBackPressedCallback; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.settings.R; +import com.android.settings.core.InstrumentedFragment; +import com.android.settings.privatespace.PrivateSpaceMaintainer; + +/** Fragment to show loading animation screen while deleting private space. */ +public class PrivateSpaceDeletionProgressFragment extends InstrumentedFragment { + private static final String TAG = "PrivateSpaceDeleteProg"; + private static final int PRIVATE_SPACE_DELETE_POST_DELAY_MS = 1000; + private Handler mHandler; + private PrivateSpaceMaintainer mPrivateSpaceMaintainer; + private Runnable mDeletePrivateSpace = + new Runnable() { + @Override + public void run() { + deletePrivateSpace(); + getActivity().finish(); + } + }; + + static class Injector { + PrivateSpaceMaintainer injectPrivateSpaceMaintainer(Context context) { + return PrivateSpaceMaintainer.getInstance(context); + } + } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + if (android.os.Flags.allowPrivateProfile()) { + super.onCreate(savedInstanceState); + } + } + + @Override + public int getMetricsCategory() { + return SettingsEnums.PRIVATE_SPACE_SETTINGS; + } + + @NonNull + @Override + public View onCreateView( + @NonNull LayoutInflater inflater, + @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + mPrivateSpaceMaintainer = + new PrivateSpaceDeletionProgressFragment.Injector() + .injectPrivateSpaceMaintainer(getActivity().getApplicationContext()); + if (!mPrivateSpaceMaintainer.doesPrivateSpaceExist()) { + // Ideally this should never happen as PS Settings is not available when there's no + // Private Profile. + Log.e(TAG, "Unexpected attempt to delete non-existent PS"); + getActivity().finish(); + } + View contentView = + inflater.inflate(R.layout.private_space_confirm_deletion, 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); + mHandler = new Handler(Looper.getMainLooper()); + // Ensures screen visibility to user by introducing a 1-second delay before deleting private + // space. + mHandler.postDelayed(mDeletePrivateSpace, PRIVATE_SPACE_DELETE_POST_DELAY_MS); + return contentView; + } + + @Override + public void onDestroy() { + mHandler.removeCallbacks(mDeletePrivateSpace); + super.onDestroy(); + } + + /** Deletes private space and shows a toast message */ + @VisibleForTesting + public void deletePrivateSpace() { + PrivateSpaceMaintainer.ErrorDeletingPrivateSpace error = + mPrivateSpaceMaintainer.deletePrivateSpace(); + if (error == DELETE_PS_ERROR_NONE) { + showSuccessfulDeletionToast(); + } else if (error == DELETE_PS_ERROR_INTERNAL) { + showDeletionInternalErrorToast(); + } + } + + @VisibleForTesting + public void setPrivateSpaceMaintainer(@NonNull Injector injector) { + mPrivateSpaceMaintainer = injector.injectPrivateSpaceMaintainer(getActivity()); + } + + /** Shows a toast saying that the private space was deleted */ + @VisibleForTesting + public void showSuccessfulDeletionToast() { + Toast.makeText(getContext(), R.string.private_space_deleted, Toast.LENGTH_SHORT).show(); + } + + /** Shows a toast saying that the private space could not be deleted */ + @VisibleForTesting + public void showDeletionInternalErrorToast() { + Toast.makeText(getContext(), R.string.private_space_delete_failed, Toast.LENGTH_SHORT) + .show(); + } +} diff --git a/tests/unit/src/com/android/settings/privatespace/DeletePrivateSpaceControllerTest.java b/tests/unit/src/com/android/settings/privatespace/DeletePrivateSpaceControllerTest.java deleted file mode 100644 index 8fb3eae9dab..00000000000 --- a/tests/unit/src/com/android/settings/privatespace/DeletePrivateSpaceControllerTest.java +++ /dev/null @@ -1,108 +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.privatespace; - -import static com.android.settings.core.BasePreferenceController.AVAILABLE; -import static com.android.settings.privatespace.PrivateSpaceMaintainer.ErrorDeletingPrivateSpace.DELETE_PS_ERROR_INTERNAL; -import static com.android.settings.privatespace.PrivateSpaceMaintainer.ErrorDeletingPrivateSpace.DELETE_PS_ERROR_NONE; -import static com.google.common.truth.Truth.assertThat; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.verify; - -import android.content.Context; - -import androidx.preference.Preference; -import androidx.test.core.app.ApplicationProvider; -import androidx.test.ext.junit.runners.AndroidJUnit4; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; - -@RunWith(AndroidJUnit4.class) -public class DeletePrivateSpaceControllerTest { - @Mock private PrivateSpaceMaintainer mPrivateSpaceMaintainer; - @Mock private Context mContext; - - private Preference mPreference; - private DeletePrivateSpaceController mDeletePrivateSpaceController; - - /** Required setup before a test. */ - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - mContext = ApplicationProvider.getApplicationContext(); - final String preferenceKey = "private_space_delete"; - - mPreference = new Preference(ApplicationProvider.getApplicationContext()); - mPreference.setKey(preferenceKey); - - mDeletePrivateSpaceController = - new DeletePrivateSpaceController( - mContext, - preferenceKey, - new DeletePrivateSpaceController.Injector() { - @Override - PrivateSpaceMaintainer injectPrivateSpaceMaintainer(Context context) { - return mPrivateSpaceMaintainer; - } - }); - } - - /** Tests that the controller is always available. */ - @Test - public void getAvailabilityStatus_returnsAvailable() { - assertThat(mDeletePrivateSpaceController.getAvailabilityStatus()).isEqualTo(AVAILABLE); - } - - /** Tests that on click it attempts to delete the PS. */ - @Test - public void handlePreferenceTreeClick_attemptsToDeletePrivateSpace() { - doReturn(DELETE_PS_ERROR_NONE).when(mPrivateSpaceMaintainer).deletePrivateSpace(); - DeletePrivateSpaceController spy = Mockito.spy(mDeletePrivateSpaceController); - doNothing().when(spy).showSuccessfulDeletionToast(); - spy.handlePreferenceTreeClick(mPreference); - - verify(mPrivateSpaceMaintainer).deletePrivateSpace(); - } - - /** Tests that on deletion of PS relevant toast is shown. */ - @Test - public void handlePreferenceTreeClick_onDeletion_showsDeletedToast() { - doReturn(DELETE_PS_ERROR_NONE).when(mPrivateSpaceMaintainer).deletePrivateSpace(); - DeletePrivateSpaceController spy = Mockito.spy(mDeletePrivateSpaceController); - doNothing().when(spy).showSuccessfulDeletionToast(); - spy.handlePreferenceTreeClick(mPreference); - - verify(spy).showSuccessfulDeletionToast(); - } - - /** Tests that on failing to delete the PS relevant toast is shown. */ - @Test - public void handlePreferenceTreeClick_onDeletionError_showsDeletionFailedToast() { - doReturn(DELETE_PS_ERROR_INTERNAL).when(mPrivateSpaceMaintainer).deletePrivateSpace(); - DeletePrivateSpaceController spy = Mockito.spy(mDeletePrivateSpaceController); - doNothing().when(spy).showDeletionInternalErrorToast(); - spy.handlePreferenceTreeClick(mPreference); - - verify(spy).showDeletionInternalErrorToast(); - } -} diff --git a/tests/unit/src/com/android/settings/privatespace/delete/DeletePrivateSpaceControllerTest.java b/tests/unit/src/com/android/settings/privatespace/delete/DeletePrivateSpaceControllerTest.java new file mode 100644 index 00000000000..371ca240039 --- /dev/null +++ b/tests/unit/src/com/android/settings/privatespace/delete/DeletePrivateSpaceControllerTest.java @@ -0,0 +1,74 @@ +/* + * 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.delete; + +import static com.android.settings.core.BasePreferenceController.AVAILABLE; +import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE; + +import static com.google.common.truth.Truth.assertThat; + +import android.content.Context; +import android.platform.test.flag.junit.SetFlagsRule; + +import androidx.preference.Preference; +import androidx.test.core.app.ApplicationProvider; +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 DeletePrivateSpaceControllerTest { + @Mock private Context mContext; + @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + private Preference mPreference; + private DeletePrivateSpaceController mDeletePrivateSpaceController; + + /** Required setup before a test. */ + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = ApplicationProvider.getApplicationContext(); + final String preferenceKey = "private_space_delete"; + + mPreference = new Preference(ApplicationProvider.getApplicationContext()); + mPreference.setKey(preferenceKey); + + mDeletePrivateSpaceController = new DeletePrivateSpaceController(mContext, preferenceKey); + } + + /** 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); + + assertThat(mDeletePrivateSpaceController.getAvailabilityStatus()).isEqualTo(AVAILABLE); + } + + /** 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); + + 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 new file mode 100644 index 00000000000..16ccbc451fc --- /dev/null +++ b/tests/unit/src/com/android/settings/privatespace/delete/PrivateSpaceDeleteFragmentTest.java @@ -0,0 +1,46 @@ +/* + * 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.delete; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.spy; + +import android.app.settings.SettingsEnums; +import android.os.Flags; +import android.platform.test.flag.junit.SetFlagsRule; + +import androidx.test.annotation.UiThreadTest; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class PrivateSpaceDeleteFragmentTest { + @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + private PrivateSpaceDeleteFragment mFragment; + + @Test + @UiThreadTest + public void verifyMetricsConstant() { + mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE); + 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 new file mode 100644 index 00000000000..5c2ef23564b --- /dev/null +++ b/tests/unit/src/com/android/settings/privatespace/delete/PrivateSpaceDeletionProgressFragmentTest.java @@ -0,0 +1,132 @@ +/* + * 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.delete; + +import static com.android.settings.privatespace.PrivateSpaceMaintainer.ErrorDeletingPrivateSpace.DELETE_PS_ERROR_INTERNAL; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; + +import android.app.settings.SettingsEnums; +import android.content.Context; +import android.os.Flags; +import android.platform.test.flag.junit.SetFlagsRule; + +import androidx.test.annotation.UiThreadTest; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import com.android.settings.privatespace.PrivateSpaceMaintainer; + +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; +import org.mockito.MockitoAnnotations; + +@RunWith(AndroidJUnit4.class) +public class PrivateSpaceDeletionProgressFragmentTest { + @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + private Context mContext; + private PrivateSpaceDeletionProgressFragment mFragment; + private PrivateSpaceMaintainer mPrivateSpaceMaintainer; + @Mock private PrivateSpaceMaintainer mPrivateSpaceMaintainerMock; + + @UiThreadTest + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + mContext = ApplicationProvider.getApplicationContext(); + mFragment = new PrivateSpaceDeletionProgressFragment(); + PrivateSpaceDeletionProgressFragment.Injector injector = + new PrivateSpaceDeletionProgressFragment.Injector() { + @Override + public PrivateSpaceMaintainer injectPrivateSpaceMaintainer(Context context) { + return mPrivateSpaceMaintainer; + } + }; + mPrivateSpaceMaintainer = PrivateSpaceMaintainer.getInstance(mContext); + mFragment.setPrivateSpaceMaintainer(injector); + } + + @After + public void tearDown() { + mPrivateSpaceMaintainer.deletePrivateSpace(); + } + + @Test + @UiThreadTest + public void verifyMetricsConstant() { + mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE); + assertThat(mFragment.getMetricsCategory()).isEqualTo(SettingsEnums.PRIVATE_SPACE_SETTINGS); + } + + /** Tests that deletePrivateSpace() deletes the private space. */ + @Test + @UiThreadTest + public void deletePrivateSpace_deletesPS() { + PrivateSpaceDeletionProgressFragment spyFragment = spy(mFragment); + doNothing().when(spyFragment).showSuccessfulDeletionToast(); + mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE); + + mPrivateSpaceMaintainer.createPrivateSpace(); + spyFragment.deletePrivateSpace(); + assertThat(mPrivateSpaceMaintainer.doesPrivateSpaceExist()).isFalse(); + } + + /** Tests that on deletion of the private space relevant toast is shown. */ + @Test + @UiThreadTest + public void deletePrivateSpace_onDeletion_showsDeletedToast() { + PrivateSpaceDeletionProgressFragment spyFragment = spy(mFragment); + doNothing().when(spyFragment).showSuccessfulDeletionToast(); + mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE); + + mPrivateSpaceMaintainer.createPrivateSpace(); + spyFragment.deletePrivateSpace(); + verify(spyFragment).showSuccessfulDeletionToast(); + } + + /** Tests that on failing to delete the private space relevant toast is shown. */ + @Test + @UiThreadTest + public void deletePrivateSpace_onDeletionError_showsDeletionFailedToast() { + PrivateSpaceDeletionProgressFragment spyFragment = + spy(new PrivateSpaceDeletionProgressFragment()); + PrivateSpaceDeletionProgressFragment.Injector injector = + new PrivateSpaceDeletionProgressFragment.Injector() { + @Override + PrivateSpaceMaintainer injectPrivateSpaceMaintainer(Context context) { + return mPrivateSpaceMaintainerMock; + } + }; + spyFragment.setPrivateSpaceMaintainer(injector); + doReturn(DELETE_PS_ERROR_INTERNAL).when(mPrivateSpaceMaintainerMock).deletePrivateSpace(); + doNothing().when(spyFragment).showDeletionInternalErrorToast(); + mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE); + + spyFragment.deletePrivateSpace(); + + verify(spyFragment).showDeletionInternalErrorToast(); + } +}