Merge tag 'android-security-10.0.0_r53' into int/10/fp2

Android security 10.0.0 release 53

* tag 'android-security-10.0.0_r53':
  [RESTRICT AUTOMERGE] Set MANAGED_PROVISIONING_DPC_DOWNLOADED when downloading DPC.

Change-Id: I64da7e94a0f1dca0e4e88d3f34e16fadfaa7aaaf
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index efc8729..0a2f82d 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -246,7 +246,7 @@
 
         <!-- TODO: Add permission for setup-wizard to guard access? -->
         <activity android:name=".finalization.FinalizationActivity"
-                android:theme="@android:style/Theme.NoDisplay"
+                android:theme="@style/SudThemeGlifV3.Light"
                 android:noHistory="true"
                 android:excludeFromRecents="true"
                 android:exported="true"
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index f1d94e9..a6a2dde 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -80,7 +80,7 @@
     <string name="device_owner_cancel_message" msgid="2529288571742712065">"¿Quieres detener la configuración y borrar los datos del dispositivo?"</string>
     <string name="device_owner_cancel_cancel" msgid="1052951540909389275">"Cancelar"</string>
     <string name="device_owner_error_ok" msgid="2002250763093787051">"Aceptar"</string>
-    <string name="reset" msgid="6467204151306265796">"Recuperar"</string>
+    <string name="reset" msgid="6467204151306265796">"Restablecer"</string>
     <string name="cant_set_up_profile" msgid="4341825293970158436">"No se ha podido configurar el perfil"</string>
     <string name="cant_set_up_device" msgid="4120090138983350714">"No se ha podido configurar el dispositivo"</string>
     <string name="couldnt_set_up_device" msgid="5137950404283642302">"No se ha podido configurar el dispositivo. Para obtener ayuda, ponte en contacto con tu administrador de TI."</string>
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index a01bce8..0cb8eae 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -155,7 +155,7 @@
     <string name="join_many_items_last" msgid="7469666990442158802">"<xliff:g id="ALL_BUT_LAST_ITEM">%1$s</xliff:g> eta <xliff:g id="LAST_ITEM_0">%2$s</xliff:g>"</string>
     <string name="join_many_items_first" msgid="8365482726853276608">"<xliff:g id="FIRST_ITEM">%1$s</xliff:g>, <xliff:g id="ALL_BUT_FIRST_AND_LAST_ITEM">%2$s</xliff:g>"</string>
     <string name="join_many_items_middle" msgid="8569294838319639963">"<xliff:g id="ADDED_ITEM">%1$s</xliff:g>, <xliff:g id="REST_OF_ITEMS">%2$s</xliff:g>"</string>
-    <string name="take_a_few_minutes" msgid="6282806501305322838">"Minutu batzuk behar izan daitezke"</string>
+    <string name="take_a_few_minutes" msgid="6282806501305322838">"Agian minutu batzuk beharko dira"</string>
     <string name="work_profile_description" msgid="8524116010729569213">"Laneko aplikazioak profil honetan gordeko dira eta zure erakundeak kudeatuko ditu"</string>
     <string name="device_owner_description" msgid="168013145812679664">"Erakundeak babestu eta kudeatuko du gailu hau"</string>
     <string name="setup_provisioning_header" msgid="4282483198266806271">"Laneko gailuaren konfigurazioa prestatzen…"</string>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index 6a01fd7..7750a32 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -167,11 +167,11 @@
     <string name="downloading_administrator_header" msgid="8660294318893902915">"Préparation pour la configuration professionnelle…"</string>
     <string name="work_profile_provisioning_accept_header" msgid="462916780311392444">"Commencez par configurer votre profil professionnel"</string>
     <string name="work_profile_provisioning_accept_header_post_suw" msgid="1353127953275291089">"Configurer votre profil professionnel"</string>
-    <string name="work_profile_provisioning_step_1_header" msgid="7914961694921466366">"Les applications professionnelles sont conservées dans votre profil professionnel"</string>
-    <string name="work_profile_provisioning_step_2_header" msgid="6001172190404670248">"Mettez vos applications professionnelles en pause lorsque vous avez fini votre journée"</string>
-    <string name="work_profile_provisioning_step_3_header" msgid="7495564624887776704">"Seules les données dans votre profil professionnel sont visibles de votre administrateur informatique"</string>
+    <string name="work_profile_provisioning_step_1_header" msgid="7914961694921466366">"Les applis professionnelles sont dans votre profil professionnel"</string>
+    <string name="work_profile_provisioning_step_2_header" msgid="6001172190404670248">"Mettez vos applis professionnelles en pause quand vous avez fini de travailler"</string>
+    <string name="work_profile_provisioning_step_3_header" msgid="7495564624887776704">"Votre administrateur informatique n\'a accès qu\'aux données du profil professionnel"</string>
     <string name="work_profile_provisioning_progress_label" msgid="2627905308998389193">"Configuration de votre profil professionnel…"</string>
-    <string name="work_profile_provisioning_summary" msgid="3917907344897144246">"Les applications professionnelles sont conservées dans votre profil professionnel. Vous pouvez mettre en pause vos applications professionnelles lorsque vous avez fini votre journée. Seules les données dans votre profil professionnel sont visibles de votre administrateur informatique."</string>
+    <string name="work_profile_provisioning_summary" msgid="3917907344897144246">"Les applications professionnelles sont conservées dans votre profil professionnel. Vous pouvez mettre en pause vos applications professionnelles lorsque vous avez fini votre journée. Votre administrateur informatique n\'a accès qu\'aux données de votre profil professionnel."</string>
     <string name="fully_managed_device_provisioning_accept_header" msgid="2944032660440403130">"Configurez votre appareil professionnel"</string>
     <string name="fully_managed_device_provisioning_step_1_header" msgid="6396274703116708592">"Gardez vos applications professionnelles à portée de main"</string>
     <string name="fully_managed_device_provisioning_step_2_header" msgid="7165472083121590030">"Cet appareil n\'est pas privé"</string>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index 5596be1..02fc67c 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -177,7 +177,7 @@
     <string name="fully_managed_device_provisioning_step_2_header" msgid="7165472083121590030">"यह डिवाइस निजी नहीं है"</string>
     <string name="fully_managed_device_provisioning_step_2_subheader" msgid="2848998570491578119">"आपका आईटी एडमिन इस डिवाइस पर आपका डेटा और गतिविधि देख सकता है."</string>
     <string name="fully_managed_device_provisioning_progress_label" msgid="3925516135130021966">"आपका डिवाइस सेट किया जा रहा है…"</string>
-    <string name="fully_managed_device_provisioning_summary" msgid="1176062866187662479">"इस डिवाइस का इस्तेमाल अपने काम से जुड़े ऐप्लिकेशन आसानी से एक्सेस करने के लिए करें. यह डिवाइस निजी नहीं है इसलिए आपके आईटी एडमिन आपका डेटा और गतिविधि देख सकते हैं. ज़्यादा जानने के लिए अपने आईटी एडमिन से संपर्क करें."</string>
+    <string name="fully_managed_device_provisioning_summary" msgid="1176062866187662479">"इस डिवाइस का इस्तेमाल अपने काम से जुड़े ऐप्लिकेशन आसानी से ऐक्सेस करने के लिए करें. यह डिवाइस निजी नहीं है इसलिए आपके आईटी एडमिन आपका डेटा और गतिविधि देख सकते हैं. ज़्यादा जानने के लिए अपने आईटी एडमिन से संपर्क करें."</string>
     <string name="fully_managed_device_provisioning_privacy_title" msgid="4017627906103556021">"निजता रिमाइंडर"</string>
     <string name="fully_managed_device_provisioning_privacy_body" msgid="2219074604343348608">"आपके आईटी एडमिन इस डिवाइस पर आपका डेटा और गतिविधि देख सकते हैं"</string>
     <string name="device_provisioning_finished" msgid="3981783240592092906">"आपका डिवाइस इस्तेमाल के लिए तैयार है!"</string>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index 1edde84..b015b13 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -53,7 +53,7 @@
     <string name="encrypt_this_device_question" msgid="8719916619866892601">"Enkripsikan perangkat ini?"</string>
     <string name="encrypt" msgid="1749320161747489212">"Enkripsikan"</string>
     <string name="continue_provisioning_notify_title" msgid="5191449100153186648">"Enkripsi selesai"</string>
-    <string name="continue_provisioning_notify_text" msgid="1066841819786425980">"Tap untuk melanjutkan penyiapan profil kerja"</string>
+    <string name="continue_provisioning_notify_text" msgid="1066841819786425980">"Ketuk untuk melanjutkan penyiapan profil kerja"</string>
     <string name="managed_provisioning_error_text" msgid="7063621174570680890">"Tidak dapat menyiapkan profil kerja Anda. Hubungi departemen TI atau coba lagi nanti."</string>
     <string name="cant_add_work_profile" msgid="9217268909964154934">"Tidak dapat menambahkan profil kerja"</string>
     <string name="cant_replace_or_remove_work_profile" msgid="7861054306792698290">"Tidak dapat menggantikan atau menghapus profil kerja"</string>
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index db2cd84..f0c71db 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -84,7 +84,7 @@
     <string name="cant_set_up_profile" msgid="4341825293970158436">"प्रोफाइल सेट करू शकत नाही"</string>
     <string name="cant_set_up_device" msgid="4120090138983350714">"डिव्हाइस सेट करू शकत नाही"</string>
     <string name="couldnt_set_up_device" msgid="5137950404283642302">"डिव्हाइस सेट करता आले नाही. मदतीसाठी, तुमच्या IT ॲडमिनशी संपर्क साधा."</string>
-    <string name="contact_your_admin_for_help" msgid="2009904021552323731">"मदतीसाठी तुमच्या IT अॅडमिनशी संपर्क साधा"</string>
+    <string name="contact_your_admin_for_help" msgid="2009904021552323731">"मदतीसाठी तुमच्या IT ॲडमिनशी संपर्क साधा"</string>
     <string name="device_already_set_up" msgid="507881934487140294">"डिव्हाइस आधीच सेट केले आहे"</string>
     <string name="error_wifi" msgid="1850288843966836571">"वाय-फाय शी कनेक्ट करता आले नाही"</string>
     <string name="device_has_reset_protection_contact_admin" msgid="2662050020376475656">"तुमच्या डिव्हाइसचे रीसेट संरक्षण सुरू केलेले आहे. मदतीसाठी, तुमच्या IT अ‍ॅडमिनशी संपर्क साधा."</string>
@@ -124,7 +124,7 @@
     <string name="set_up_your_device" msgid="1896651520959894681">"तुमचे डिव्हाइस सेट करा"</string>
     <string name="info_anim_title_0" msgid="3285414600215959704">"तुम्ही ज्या पद्धतीने कार्य करता ती पद्धत बदला"</string>
     <string name="info_anim_title_1" msgid="2657512519467714760">"वैैयक्तिक मधून कार्य स्वतंत्र करा"</string>
-    <string name="one_place_for_work_apps" msgid="2595597562302953960">"कार्यसंबंधित अॅप्ससाठी एक ठिकाण"</string>
+    <string name="one_place_for_work_apps" msgid="2595597562302953960">"कार्यसंबंधित ॲप्ससाठी एक ठिकाण"</string>
     <string name="info_anim_title_2" msgid="4629781398620470204">"तुमचे काम पूर्ण झाल्‍यानंतर बंद करा"</string>
     <string name="provisioning" msgid="4512493827019163451">"तरतूद"</string>
     <string name="copying_certs" msgid="5697938664953550881">"CA प्रमाणपत्रे सेट करत आहे"</string>
diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml
index 0af3065..ef243ab 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -70,7 +70,7 @@
     <string name="progress_connect_to_mobile_network" msgid="3852054186860657088">"மொபைல் நெட்வொர்க்குடன் இணைக்கிறது…"</string>
     <string name="progress_download" msgid="3522436271691064624">"நிர்வாகி ஆப்ஸை இறக்குகிறது…"</string>
     <string name="progress_install" msgid="2258045670385866183">"நிர்வாகி ஆப்ஸை நிறுவுகிறது…"</string>
-    <string name="progress_delete_non_required_apps" msgid="7633458399262691256">"தேவையற்ற சாதனப் பயன்பாடுகளை அகற்றுகிறது…"</string>
+    <string name="progress_delete_non_required_apps" msgid="7633458399262691256">"தேவையற்ற சாதன ஆப்ஸை அகற்றுகிறது…"</string>
     <string name="progress_finishing_touches" msgid="9037776404089697198">"இறுதியாகச் சில விஷயங்களைச் சேர்க்கிறது…"</string>
     <string name="progress_set_owner" msgid="8214062820093757961">"சாதன உரிமையாளரை அமைக்கிறது…"</string>
     <string name="progress_initialize" msgid="1104643492713424939">"சாதனத்தைத் தொடங்குகிறது…"</string>
@@ -124,13 +124,13 @@
     <string name="set_up_your_device" msgid="1896651520959894681">"சாதனத்தை அமைக்கவும்"</string>
     <string name="info_anim_title_0" msgid="3285414600215959704">"நீங்கள் வேலை செய்யும் விதத்தை மாற்றலாம்"</string>
     <string name="info_anim_title_1" msgid="2657512519467714760">"தனிப்பட்ட தரவிலிருந்து பணித் தரவைப் பிரிக்கலாம்"</string>
-    <string name="one_place_for_work_apps" msgid="2595597562302953960">"பணி தொடர்பான பயன்பாடுகள் அனைத்தும் ஒரே இடத்தில்"</string>
+    <string name="one_place_for_work_apps" msgid="2595597562302953960">"பணி தொடர்பான ஆப்ஸ் அனைத்தும் ஒரே இடத்தில்"</string>
     <string name="info_anim_title_2" msgid="4629781398620470204">"முடித்ததும், பணியை முடக்கவும்"</string>
     <string name="provisioning" msgid="4512493827019163451">"அமைக்கிறது"</string>
     <string name="copying_certs" msgid="5697938664953550881">"CA சான்றிதழ்களை அமைக்கிறது"</string>
     <string name="setup_profile" msgid="5573950582159698549">"சுயவிவரத்தை அமைக்கவும்"</string>
     <string name="profile_benefits_description" msgid="758432985984252636">"பணி விவரத்தைப் பயன்படுத்துவதன் மூலம், பணித் தரவையும் தனிப்பட்ட தரவையும் தனித்தனியாகப் பிரிக்கலாம்"</string>
-    <string name="comp_profile_benefits_description" msgid="379837075456998273">"பணி விவரத்தைப் பயன்படுத்துவதன் மூலம், பணி தொடர்பான பயன்பாடுகளை ஒரே இடத்தில் வைத்திருக்கலாம்"</string>
+    <string name="comp_profile_benefits_description" msgid="379837075456998273">"பணி விவரத்தைப் பயன்படுத்துவதன் மூலம், பணி தொடர்பான ஆப்ஸை ஒரே இடத்தில் வைத்திருக்கலாம்"</string>
     <string name="setup_profile_encryption" msgid="5241291404536277038">"சுயவிவரத்தை அமைக்கவும். என்க்ரிப்ட்"</string>
     <string name="setup_profile_progress" msgid="7742718527853325656">"சுயவிவரத்தை அமைக்கவும். செயல்நிலையைக் காட்டுகிறது"</string>
     <string name="setup_device" msgid="6725265673245816366">"சாதனத்தை அமை"</string>
diff --git a/src/com/android/managedprovisioning/common/Utils.java b/src/com/android/managedprovisioning/common/Utils.java
index 987e117..6bbe2db 100644
--- a/src/com/android/managedprovisioning/common/Utils.java
+++ b/src/com/android/managedprovisioning/common/Utils.java
@@ -25,6 +25,11 @@
 import static android.app.admin.DevicePolicyManager.PROVISIONING_TRIGGER_CLOUD_ENROLLMENT;
 import static android.app.admin.DevicePolicyManager.PROVISIONING_TRIGGER_QR_CODE;
 import static android.app.admin.DevicePolicyManager.PROVISIONING_TRIGGER_UNSPECIFIED;
+import static android.content.pm.PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS;
+import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
 import static android.nfc.NfcAdapter.ACTION_NDEF_DISCOVERED;
 
 import static com.android.managedprovisioning.common.Globals.ACTION_PROVISION_MANAGED_DEVICE_SILENTLY;
@@ -33,6 +38,7 @@
 import static com.android.managedprovisioning.model.ProvisioningParams.PROVISIONING_MODE_MANAGED_PROFILE_ON_FULLY_NAMAGED_DEVICE;
 
 import android.annotation.WorkerThread;
+import android.net.NetworkCapabilities;
 import android.os.Handler;
 import android.os.Looper;
 import com.android.managedprovisioning.R;
@@ -90,8 +96,10 @@
 import java.io.InputStream;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Objects;
 import java.util.Set;
 
 import com.google.android.setupdesign.GlifLayout;
@@ -124,7 +132,8 @@
         List<ApplicationInfo> aInfos = null;
         try {
             aInfos = ipm.getInstalledApplications(
-                    PackageManager.MATCH_UNINSTALLED_PACKAGES, userId).getList();
+                    MATCH_UNINSTALLED_PACKAGES | MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS, userId)
+                    .getList();
         } catch (RemoteException neverThrown) {
             ProvisionLogger.loge("This should not happen.", neverThrown);
         }
@@ -598,6 +607,27 @@
         return info != null && info.isConnected();
     }
 
+    public boolean isMobileNetworkConnectedToInternet(Context context) {
+        final ConnectivityManager connectivityManager =
+                (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+        return Arrays.stream(connectivityManager.getAllNetworks())
+                .filter(network -> {
+                    return Objects.nonNull(connectivityManager.getNetworkCapabilities(network));
+                })
+                .map(connectivityManager::getNetworkCapabilities)
+                .filter(this::isCellularNetwork)
+                .anyMatch(this::isConnectedToInternet);
+    }
+
+    private boolean isConnectedToInternet(NetworkCapabilities capabilities) {
+        return capabilities.hasCapability(NET_CAPABILITY_INTERNET)
+                && capabilities.hasCapability(NET_CAPABILITY_VALIDATED);
+    }
+
+    private boolean isCellularNetwork(NetworkCapabilities capabilities) {
+        return capabilities.hasTransport(TRANSPORT_CELLULAR);
+    }
+
     /**
      * Returns whether the device is currently connected to a wifi.
      */
diff --git a/src/com/android/managedprovisioning/finalization/FinalizationActivity.java b/src/com/android/managedprovisioning/finalization/FinalizationActivity.java
index ea3612f..16093fd 100644
--- a/src/com/android/managedprovisioning/finalization/FinalizationActivity.java
+++ b/src/com/android/managedprovisioning/finalization/FinalizationActivity.java
@@ -36,7 +36,13 @@
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-        new FinalizationController(this).provisioningFinalized();
-        finish();
+        // To prevent b/131315856, we finish this activity now only if we do not expect to launch
+        // the admin app. Otherwise let android:noHistory automatically finish it.
+        final FinalizationController finalizationController = new FinalizationController(this);
+        finalizationController.provisioningFinalized();
+        final int result = finalizationController.getProvisioningFinalizedResult();
+        if (result != FinalizationController.PROVISIONING_FINALIZED_RESULT_ADMIN_WILL_LAUNCH) {
+            finish();
+        }
     }
 }
diff --git a/src/com/android/managedprovisioning/finalization/FinalizationController.java b/src/com/android/managedprovisioning/finalization/FinalizationController.java
index 1ea806e..ba09868 100644
--- a/src/com/android/managedprovisioning/finalization/FinalizationController.java
+++ b/src/com/android/managedprovisioning/finalization/FinalizationController.java
@@ -22,6 +22,7 @@
 import static com.android.internal.util.Preconditions.checkNotNull;
 import static com.android.managedprovisioning.finalization.SendDpcBroadcastService.EXTRA_PROVISIONING_PARAMS;
 
+import android.annotation.IntDef;
 import android.app.NotificationManager;
 import android.app.admin.DevicePolicyManager;
 import android.content.ComponentName;
@@ -51,6 +52,14 @@
 public class FinalizationController {
     private static final String PROVISIONING_PARAMS_FILE_NAME =
             "finalization_activity_provisioning_params.xml";
+    static final int PROVISIONING_FINALIZED_RESULT_DEFAULT = 1;
+    static final int PROVISIONING_FINALIZED_RESULT_ADMIN_WILL_LAUNCH = 2;
+    static final int PROVISIONING_FINALIZED_RESULT_EARLY_EXIT = 3;
+    @IntDef({
+            PROVISIONING_FINALIZED_RESULT_DEFAULT,
+            PROVISIONING_FINALIZED_RESULT_ADMIN_WILL_LAUNCH,
+            PROVISIONING_FINALIZED_RESULT_EARLY_EXIT})
+    @interface ProvisioningFinalizedResult {}
 
     private final Context mContext;
     private final Utils mUtils;
@@ -59,6 +68,7 @@
     private final ProvisioningIntentProvider mProvisioningIntentProvider;
     private final NotificationHelper mNotificationHelper;
     private final DeferredMetricsReader mDeferredMetricsReader;
+    private @ProvisioningFinalizedResult int mProvisioningFinalizedResult;
 
     public FinalizationController(Context context,
           UserProvisioningStateHelper userProvisioningStateHelper) {
@@ -171,9 +181,13 @@
      * <p>This method has to be invoked after {@link #provisioningInitiallyDone(ProvisioningParams)}
      * was called. It is commonly invoked at the end of SUW if provisioning occurs during SUW. It
      * loads the provisioning params from the storage, notifies the DPC about the completed
-     * provisioning and sets the right user provisioning states.</p>
+     * provisioning and sets the right user provisioning states.
+     *
+     * <p>To retrieve the resulting state of this method, use
+     * {@link #getProvisioningFinalizedResult()}
      */
     void provisioningFinalized() {
+        mProvisioningFinalizedResult = PROVISIONING_FINALIZED_RESULT_EARLY_EXIT;
         mDeferredMetricsReader.scheduleDumpMetrics(mContext);
 
         if (mUserProvisioningStateHelper.isStateUnmanagedOrFinalized()) {
@@ -188,6 +202,7 @@
             return;
         }
 
+        mProvisioningFinalizedResult = PROVISIONING_FINALIZED_RESULT_DEFAULT;
         if (mUtils.isAdminIntegratedFlow(params)) {
             // Don't send ACTION_PROFILE_PROVISIONING_COMPLETE broadcast to DPC or launch DPC by
             // ACTION_PROVISIONING_SUCCESSFUL intent if it's admin integrated flow.
@@ -202,6 +217,12 @@
         } else {
             if (params.provisioningAction.equals(ACTION_PROVISION_MANAGED_PROFILE)) {
                 notifyDpcManagedProfile(params);
+                final UserHandle managedProfileUserHandle = mUtils.getManagedProfile(mContext);
+                final int userId = managedProfileUserHandle.getIdentifier();
+                mProvisioningFinalizedResult =
+                        mProvisioningIntentProvider.canLaunchDpc(params, userId, mUtils, mContext)
+                        ? PROVISIONING_FINALIZED_RESULT_ADMIN_WILL_LAUNCH
+                        : PROVISIONING_FINALIZED_RESULT_DEFAULT;
             } else {
                 // For managed user and device owner, we send the provisioning complete intent and
                 // maybe launch the DPC.
@@ -226,6 +247,16 @@
     }
 
     /**
+     * @throws IllegalStateException if {@link #provisioningFinalized()} was not called before.
+     */
+    @ProvisioningFinalizedResult int getProvisioningFinalizedResult() {
+        if (mProvisioningFinalizedResult == 0) {
+            throw new IllegalStateException("provisioningFinalized() has not been called.");
+        }
+        return mProvisioningFinalizedResult;
+    }
+
+    /**
      * Start a service which notifies the DPC on the managed profile that provisioning has
      * completed. When the DPC has received the intent, send notify the primary instance that the
      * profile is ready. The service is needed to prevent the managed provisioning process from
diff --git a/src/com/android/managedprovisioning/finalization/ProvisioningIntentProvider.java b/src/com/android/managedprovisioning/finalization/ProvisioningIntentProvider.java
index 1311200..6627456 100644
--- a/src/com/android/managedprovisioning/finalization/ProvisioningIntentProvider.java
+++ b/src/com/android/managedprovisioning/finalization/ProvisioningIntentProvider.java
@@ -44,6 +44,11 @@
         }
     }
 
+    boolean canLaunchDpc(ProvisioningParams params, int userId, Utils utils, Context context) {
+        final Intent dpcLaunchIntent = createDpcLaunchIntent(params);
+        return utils.canResolveIntentAsUser(context, dpcLaunchIntent, userId);
+    }
+
     Intent createProvisioningCompleteIntent(
             @NonNull ProvisioningParams params, int userId, Utils utils, Context context) {
         Intent intent = new Intent(ACTION_PROFILE_PROVISIONING_COMPLETE);
diff --git a/src/com/android/managedprovisioning/preprovisioning/PreProvisioningController.java b/src/com/android/managedprovisioning/preprovisioning/PreProvisioningController.java
index 82d6fd3..62d4414 100644
--- a/src/com/android/managedprovisioning/preprovisioning/PreProvisioningController.java
+++ b/src/com/android/managedprovisioning/preprovisioning/PreProvisioningController.java
@@ -288,9 +288,7 @@
         if (isDeviceOwnerProvisioning()) {
             // TODO: make a general test based on deviceAdminDownloadInfo field
             // PO doesn't ever initialize that field, so OK as a general case
-            if (!mUtils.isConnectedToNetwork(mContext) && mParams.wifiInfo == null
-                    && mParams.deviceAdminDownloadInfo != null
-                    && !mParams.useMobileData) {
+            if (shouldShowWifiPicker()) {
                 // Have the user pick a wifi network if necessary.
                 // It is not possible to ask the user to pick a wifi network if
                 // the screen is locked.
@@ -326,6 +324,22 @@
         }
     }
 
+    private boolean shouldShowWifiPicker() {
+        if (mParams.wifiInfo != null) {
+            return false;
+        }
+        if (mParams.deviceAdminDownloadInfo == null) {
+            return false;
+        }
+        if (mUtils.isConnectedToWifi(mContext)) {
+            return false;
+        }
+        if (mParams.useMobileData) {
+            return !mUtils.isMobileNetworkConnectedToInternet(mContext);
+        }
+        return true;
+    }
+
     void showUserConsentScreen() {
         // Check whether provisioning is allowed for the current action
         if (!checkDevicePolicyPreconditions()) {
diff --git a/src/com/android/managedprovisioning/provisioning/ProvisioningActivity.java b/src/com/android/managedprovisioning/provisioning/ProvisioningActivity.java
index fe2a937..cbfd31c 100644
--- a/src/com/android/managedprovisioning/provisioning/ProvisioningActivity.java
+++ b/src/com/android/managedprovisioning/provisioning/ProvisioningActivity.java
@@ -139,20 +139,20 @@
         // TODO: call this for the new flow after new NFC flow has been added
         // maybeLaunchNfcUserSetupCompleteIntent();
 
-        if (mParams.skipEducationScreens || mTransitionAnimationHelper.areAllTransitionsShown()) {
+        if (shouldSkipEducationScreens() || mTransitionAnimationHelper.areAllTransitionsShown()) {
             updateProvisioningFinalizedScreen();
         }
         mState = STATE_PROVISIONING_FINALIZED;
     }
 
     private void updateProvisioningFinalizedScreen() {
-        if (!mParams.skipEducationScreens) {
+        if (!shouldSkipEducationScreens()) {
             final GlifLayout layout = findViewById(R.id.setup_wizard_layout);
             layout.findViewById(R.id.provisioning_progress).setVisibility(View.GONE);
             mNextButton.setVisibility(View.VISIBLE);
         }
 
-        if (mParams.skipEducationScreens || Utils.isSilentProvisioning(this, mParams)) {
+        if (shouldSkipEducationScreens() || Utils.isSilentProvisioning(this, mParams)) {
             onNextButtonClicked();
         }
     }
@@ -296,7 +296,7 @@
     @Override
     protected void onStart() {
         super.onStart();
-        if (mParams.skipEducationScreens) {
+        if (shouldSkipEducationScreens()) {
             startSpinnerAnimation();
         } else {
             startTransitionAnimation();
@@ -306,7 +306,7 @@
     @Override
     protected void onStop() {
         super.onStop();
-        if (mParams.skipEducationScreens) {
+        if (shouldSkipEducationScreens()) {
             endSpinnerAnimation();
         } else {
             endTransitionAnimation();
@@ -347,7 +347,7 @@
         final int progressLabelResId =
                 PROVISIONING_MODE_TO_PROGRESS_LABEL.get(getProvisioningMode());
         final TextView progressLabel = layout.findViewById(R.id.provisioning_progress);
-        if (mParams.skipEducationScreens) {
+        if (shouldSkipEducationScreens()) {
             header.setText(progressLabelResId);
             progressLabel.setVisibility(View.INVISIBLE);
             layout.findViewById(R.id.subheader).setVisibility(View.INVISIBLE);
@@ -429,4 +429,9 @@
         mRepeatingVectorAnimation.stop();
         mRepeatingVectorAnimation = null;
     }
+
+    private boolean shouldSkipEducationScreens() {
+        return mParams.skipEducationScreens
+                || getProvisioningMode() == PROVISIONING_MODE_WORK_PROFILE_ON_FULLY_MANAGED_DEVICE;
+    }
 }
\ No newline at end of file
diff --git a/src/com/android/managedprovisioning/provisioning/TransitionAnimationHelper.java b/src/com/android/managedprovisioning/provisioning/TransitionAnimationHelper.java
index 15234d9..9f53859 100644
--- a/src/com/android/managedprovisioning/provisioning/TransitionAnimationHelper.java
+++ b/src/com/android/managedprovisioning/provisioning/TransitionAnimationHelper.java
@@ -70,17 +70,6 @@
                 /* showContactAdmin */ true)
     }, R.string.fully_managed_device_provisioning_summary);
 
-    @VisibleForTesting
-    static final ProvisioningModeWrapper WORK_PROFILE_ON_FULLY_MANAGED_DEVICE_WRAPPER
-            = new ProvisioningModeWrapper(new TransitionScreenWrapper[] {
-        new TransitionScreenWrapper(R.string.fully_managed_device_provisioning_step_1_header,
-                R.drawable.connect_on_the_go_animation),
-        new TransitionScreenWrapper(R.string.fully_managed_device_provisioning_step_2_header,
-                R.drawable.not_private_animation,
-                R.string.fully_managed_device_provisioning_step_2_subheader,
-                /* showContactAdmin */ true)
-    }, R.string.fully_managed_device_provisioning_summary);
-
     private static final int TRANSITION_TIME_MILLIS = 5000;
     private static final int CROSSFADE_ANIMATION_DURATION_MILLIS = 500;
 
@@ -222,8 +211,6 @@
                 return WORK_PROFILE_WRAPPER;
             case PROVISIONING_MODE_FULLY_MANAGED_DEVICE:
                 return FULLY_MANAGED_DEVICE_WRAPPER;
-            case PROVISIONING_MODE_WORK_PROFILE_ON_FULLY_MANAGED_DEVICE:
-                return WORK_PROFILE_ON_FULLY_MANAGED_DEVICE_WRAPPER;
         }
         throw new IllegalStateException("Unexpected provisioning mode " + provisioningMode);
     }
diff --git a/src/com/android/managedprovisioning/task/InstallPackageTask.java b/src/com/android/managedprovisioning/task/InstallPackageTask.java
index efce83c..02a7ce3 100644
--- a/src/com/android/managedprovisioning/task/InstallPackageTask.java
+++ b/src/com/android/managedprovisioning/task/InstallPackageTask.java
@@ -15,6 +15,9 @@
  */
 package com.android.managedprovisioning.task;
 
+import static android.content.pm.PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS;
+import static android.content.pm.PackageManager.INSTALL_REPLACE_EXISTING;
+
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent
         .PROVISIONING_INSTALL_PACKAGE_TASK_MS;
 import static com.android.internal.util.Preconditions.checkNotNull;
@@ -126,7 +129,7 @@
             return;
         }
 
-        int installFlags = PackageManager.INSTALL_REPLACE_EXISTING;
+        int installFlags = INSTALL_REPLACE_EXISTING | INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS;
         // Current device owner (if exists) must be test-only, so it is fine to replace it with a
         // test-only package of same package name. No need to further verify signature as
         // installation will fail if signatures don't match.
diff --git a/tests/instrumentation/src/com/android/managedprovisioning/common/UtilsTest.java b/tests/instrumentation/src/com/android/managedprovisioning/common/UtilsTest.java
index dbf83ea..54c0479 100644
--- a/tests/instrumentation/src/com/android/managedprovisioning/common/UtilsTest.java
+++ b/tests/instrumentation/src/com/android/managedprovisioning/common/UtilsTest.java
@@ -16,6 +16,9 @@
 
 package com.android.managedprovisioning.common;
 
+import static android.content.pm.PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS;
+import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
+
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.anyInt;
 import static org.mockito.Mockito.eq;
@@ -49,6 +52,7 @@
 import java.util.Arrays;
 import java.util.List;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 /**
  * Unit-tests for {@link Utils}.
@@ -57,6 +61,7 @@
 public class UtilsTest extends AndroidTestCase {
     private static final String TEST_PACKAGE_NAME_1 = "com.test.packagea";
     private static final String TEST_PACKAGE_NAME_2 = "com.test.packageb";
+    private static final String TEST_PACKAGE_NAME_3 = "com.test.packagec";
     private static final String TEST_DEVICE_ADMIN_NAME = TEST_PACKAGE_NAME_1 + ".DeviceAdmin";
     // Another DeviceAdmin in package 1
     private static final String TEST_DEVICE_ADMIN_NAME_2 = TEST_PACKAGE_NAME_1 + ".DeviceAdmin2";
@@ -97,17 +102,30 @@
 
     public void testGetCurrentSystemApps() throws Exception {
         // GIVEN two currently installed apps, one of which is system
-        List<ApplicationInfo> appList = Arrays.asList(
-                createApplicationInfo(TEST_PACKAGE_NAME_1, false),
-                createApplicationInfo(TEST_PACKAGE_NAME_2, true));
+        final List<ApplicationInfo> systemAppsWithHiddenUntilInstalled = Arrays.asList(
+                createApplicationInfo(
+                        TEST_PACKAGE_NAME_1, /* system */ false, /* hiddenUntilInstalled */ false),
+                createApplicationInfo(
+                        TEST_PACKAGE_NAME_2, /* system */ true, /* hiddenUntilInstalled */ false),
+                createApplicationInfo(
+                        TEST_PACKAGE_NAME_3, /* system */ true, /* hiddenUntilInstalled */ true));
+        final List<ApplicationInfo> systemApps =
+                systemAppsWithHiddenUntilInstalled.stream()
+                        .filter(applicationInfo -> !applicationInfo.hiddenUntilInstalled)
+                        .collect(Collectors.toList());
         when(mockIPackageManager.getInstalledApplications(
-                PackageManager.MATCH_UNINSTALLED_PACKAGES, TEST_USER_ID))
-                .thenReturn(new ParceledListSlice<ApplicationInfo>(appList));
+                MATCH_UNINSTALLED_PACKAGES, TEST_USER_ID))
+                .thenReturn(new ParceledListSlice<>(systemApps));
+        when(mockIPackageManager.getInstalledApplications(
+                MATCH_UNINSTALLED_PACKAGES | MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS, TEST_USER_ID))
+                .thenReturn(new ParceledListSlice<>(systemAppsWithHiddenUntilInstalled));
+
         // WHEN requesting the current system apps
         Set<String> res = mUtils.getCurrentSystemApps(mockIPackageManager, TEST_USER_ID);
-        // THEN the one system app should be returned
-        assertEquals(1, res.size());
+        // THEN two system apps should be returned
+        assertEquals(2, res.size());
         assertTrue(res.contains(TEST_PACKAGE_NAME_2));
+        assertTrue(res.contains(TEST_PACKAGE_NAME_3));
     }
 
     public void testSetComponentEnabledSetting() throws Exception {
@@ -392,12 +410,14 @@
         assertTrue(mUtils.canResolveIntentAsUser(mockContext, intent, TEST_USER_ID));
     }
 
-    private ApplicationInfo createApplicationInfo(String packageName, boolean system) {
+    private ApplicationInfo createApplicationInfo(
+            String packageName, boolean system, boolean hiddenUntilInstalled) {
         ApplicationInfo ai = new ApplicationInfo();
         ai.packageName = packageName;
         if (system) {
             ai.flags = ApplicationInfo.FLAG_SYSTEM;
         }
+        ai.hiddenUntilInstalled = hiddenUntilInstalled;
         return ai;
     }
 
diff --git a/tests/instrumentation/src/com/android/managedprovisioning/preprovisioning/PreProvisioningControllerTest.java b/tests/instrumentation/src/com/android/managedprovisioning/preprovisioning/PreProvisioningControllerTest.java
index c9034e6..3961876 100644
--- a/tests/instrumentation/src/com/android/managedprovisioning/preprovisioning/PreProvisioningControllerTest.java
+++ b/tests/instrumentation/src/com/android/managedprovisioning/preprovisioning/PreProvisioningControllerTest.java
@@ -16,8 +16,7 @@
 package com.android.managedprovisioning.preprovisioning;
 
 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE;
-import static android.app.admin.DevicePolicyManager
-        .ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE;
+import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE;
 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE;
 import static android.app.admin.DevicePolicyManager.CODE_MANAGED_USERS_NOT_SUPPORTED;
 import static android.app.admin.DevicePolicyManager.CODE_OK;
@@ -36,8 +35,6 @@
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
-import static java.util.Collections.emptyList;
-
 import android.app.ActivityManager;
 import android.app.KeyguardManager;
 import android.app.admin.DevicePolicyManager;
@@ -53,11 +50,12 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.service.persistentdata.PersistentDataBlockManager;
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.SmallTest;
 import android.test.AndroidTestCase;
 import android.text.TextUtils;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+
 import com.android.managedprovisioning.R;
 import com.android.managedprovisioning.analytics.TimeLogger;
 import com.android.managedprovisioning.common.IllegalProvisioningArgumentException;
@@ -647,38 +645,59 @@
         verify(mUi).startProvisioning(mUserManager.getUserHandle(), mParams);
     }
 
-    public void testInitiateProvisioning_doWithDownloadInfoAndUseMobileDataFalse_showsWifiPicker()
-            throws Exception {
-        final ProvisioningParams params = createProvisioningParamsBuilder()
-                .setProvisioningAction(ACTION_PROVISION_MANAGED_DEVICE)
-                .setDeviceAdminDownloadInfo(PACKAGE_DOWNLOAD_INFO)
-                .setUseMobileData(false)
+    public void testInitiateProvisioning_showsWifiPicker() {
+        final ProvisioningParams params = createProvisioningParamsBuilderForInitiateProvisioning()
                 .build();
         initiateProvisioning(params);
         verify(mUi).requestWifiPick();
     }
 
-    public void testInitiateProvisioning_doWithNoDownloadInfoAndUseMobileDataFalse_noWifiPicker()
-            throws Exception {
-        final ProvisioningParams params = createProvisioningParamsBuilder()
-                .setProvisioningAction(ACTION_PROVISION_MANAGED_DEVICE)
+    public void testInitiateProvisioning_useMobileData_showsWifiPicker() {
+        final ProvisioningParams params = createProvisioningParamsBuilderForInitiateProvisioning()
+                .setUseMobileData(true)
+                .build();
+        initiateProvisioning(params);
+        verify(mUi).requestWifiPick();
+    }
+
+    public void testInitiateProvisioning_useMobileData_noWifiPicker() {
+        when(mUtils.isMobileNetworkConnectedToInternet(mContext)).thenReturn(true);
+        final ProvisioningParams params = createProvisioningParamsBuilderForInitiateProvisioning()
                 .setUseMobileData(true)
                 .build();
         initiateProvisioning(params);
         verify(mUi, never()).requestWifiPick();
     }
 
-    public void testInitiateProvisioning_doWithDownloadInfoAndUseMobileDataTrue_noWifiPicker()
-            throws Exception {
-        final ProvisioningParams params = createProvisioningParamsBuilder()
-                .setProvisioningAction(ACTION_PROVISION_MANAGED_DEVICE)
-                .setDeviceAdminDownloadInfo(PACKAGE_DOWNLOAD_INFO)
-                .setUseMobileData(true)
+    public void testInitiateProvisioning_connectedToWifi_noWifiPicker() {
+        when(mUtils.isConnectedToWifi(mContext)).thenReturn(true);
+        final ProvisioningParams params = createProvisioningParamsBuilderForInitiateProvisioning()
                 .build();
         initiateProvisioning(params);
         verify(mUi, never()).requestWifiPick();
     }
 
+    public void testInitiateProvisioning_noAdminDownloadInfo_noWifiPicker() {
+        final ProvisioningParams params = createProvisioningParamsBuilderForInitiateProvisioning()
+                .setDeviceAdminDownloadInfo(null)
+                .build();
+        initiateProvisioning(params);
+        verify(mUi, never()).requestWifiPick();
+    }
+
+    public void testInitiateProvisioning_wifiInfo_noWifiPicker() {
+        final ProvisioningParams params = createProvisioningParamsBuilderForInitiateProvisioning()
+                .setWifiInfo(new WifiInfo.Builder().setSsid(TEST_WIFI_SSID).build())
+                .build();
+        initiateProvisioning(params);
+        verify(mUi, never()).requestWifiPick();
+    }
+
+    private ProvisioningParams.Builder createProvisioningParamsBuilderForInitiateProvisioning() {
+        return createProvisioningParamsBuilder()
+                .setDeviceAdminDownloadInfo(PACKAGE_DOWNLOAD_INFO);
+    }
+
     private void prepareMocksForMaybeStartProvisioning(
             boolean skipUserConsent, boolean skipEncryption, boolean managedProfileExists)
             throws IllegalProvisioningArgumentException {
diff --git a/tests/instrumentation/src/com/android/managedprovisioning/task/InstallPackageTaskTest.java b/tests/instrumentation/src/com/android/managedprovisioning/task/InstallPackageTaskTest.java
index 2083b07..51969ef 100644
--- a/tests/instrumentation/src/com/android/managedprovisioning/task/InstallPackageTaskTest.java
+++ b/tests/instrumentation/src/com/android/managedprovisioning/task/InstallPackageTaskTest.java
@@ -18,6 +18,7 @@
 
 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE;
 import static android.content.pm.PackageManager.INSTALL_ALLOW_TEST;
+import static android.content.pm.PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS;
 import static android.content.pm.PackageManager.INSTALL_REPLACE_EXISTING;
 
 import static com.android.managedprovisioning.task.InstallPackageTask.ERROR_INSTALLATION_FAILED;
@@ -141,7 +142,8 @@
         mTask.run(TEST_USER_ID);
 
         // THEN package installed is invoked with an install observer
-        IntentSender observer = verifyPackageInstalled(INSTALL_REPLACE_EXISTING);
+        IntentSender observer = verifyPackageInstalled(
+                INSTALL_REPLACE_EXISTING | INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS);
 
         // WHEN the package installed callback is invoked with success
         Intent fillIn = new Intent();
@@ -166,7 +168,8 @@
 
         // THEN package installed is invoked with an install observer
         IntentSender observer = verifyPackageInstalled(
-                INSTALL_REPLACE_EXISTING | INSTALL_ALLOW_TEST);
+                INSTALL_REPLACE_EXISTING | INSTALL_ALLOW_TEST
+                        | INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS);
 
         // WHEN the package installed callback is invoked with success
         Intent fillIn = new Intent();
@@ -189,7 +192,8 @@
         mTask.run(TEST_USER_ID);
 
         // THEN package installed is invoked with an install observer
-        IntentSender observer = verifyPackageInstalled(INSTALL_REPLACE_EXISTING);
+        IntentSender observer = verifyPackageInstalled(
+                INSTALL_REPLACE_EXISTING | INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS);
 
         // WHEN the package installed callback is invoked with version downgrade error
         Intent fillIn = new Intent();
@@ -213,7 +217,8 @@
         mTask.run(TEST_USER_ID);
 
         // THEN package installed is invoked with an install observer
-        IntentSender observer = verifyPackageInstalled(INSTALL_REPLACE_EXISTING);
+        IntentSender observer = verifyPackageInstalled(
+                INSTALL_REPLACE_EXISTING | INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS);
 
         // WHEN the package installed callback is invoked with version invalid apk error
         Intent fillIn = new Intent();
@@ -237,7 +242,8 @@
         mTask.run(TEST_USER_ID);
 
         // THEN package installed is invoked with an install observer
-        IntentSender observer = verifyPackageInstalled(INSTALL_REPLACE_EXISTING);
+        IntentSender observer = verifyPackageInstalled(
+                INSTALL_REPLACE_EXISTING | INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS);
 
         // WHEN the package installed callback is invoked with the wrong package
         Intent fillIn = new Intent();