Fix provision failure behavior

Test: atest DeviceLockControllerRoboTests
Fix: 296578494

Change-Id: Ieac79c87a51490eab0e4a8f8a41a9392c9dd0bf7
diff --git a/DeviceLockController/res/layout/fragment_device_policies.xml b/DeviceLockController/res/layout/fragment_device_policies.xml
index e80bb36..bd457fa 100644
--- a/DeviceLockController/res/layout/fragment_device_policies.xml
+++ b/DeviceLockController/res/layout/fragment_device_policies.xml
@@ -77,6 +77,7 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:text="@string/next"
+            android:visibility="gone"
             app:layout_constraintTop_toTopOf="parent"
             app:layout_constraintEnd_toEndOf="parent" />
     </androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/DeviceLockController/res/layout/fragment_provision_info.xml b/DeviceLockController/res/layout/fragment_provision_info.xml
index 459ea80..c9ac059 100644
--- a/DeviceLockController/res/layout/fragment_provision_info.xml
+++ b/DeviceLockController/res/layout/fragment_provision_info.xml
@@ -85,6 +85,7 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:text="@string/previous"
+            android:visibility="gone"
             app:layout_constraintBottom_toBottomOf="parent"
             app:layout_constraintStart_toStartOf="parent" />
         <Button
@@ -92,6 +93,7 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:text="@string/next"
+            android:visibility="gone"
             app:layout_constraintBottom_toBottomOf="parent"
             app:layout_constraintEnd_toEndOf="parent" />
     </androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/DeviceLockController/src/com/android/devicelockcontroller/AbstractDeviceLockControllerScheduler.java b/DeviceLockController/src/com/android/devicelockcontroller/AbstractDeviceLockControllerScheduler.java
index d616d09..e85b5dd 100644
--- a/DeviceLockController/src/com/android/devicelockcontroller/AbstractDeviceLockControllerScheduler.java
+++ b/DeviceLockController/src/com/android/devicelockcontroller/AbstractDeviceLockControllerScheduler.java
@@ -68,9 +68,9 @@
     public abstract void scheduleResetDeviceAlarm();
 
     /**
-     * Schedule an alarm to factory reset the device with a given delay.
+     * Schedule an alarm to factory reset the device in case of mandatory provision is failed.
      */
-    public abstract void scheduleResetDeviceAlarm(Duration delay);
+    public abstract void scheduleMandatoryResetDeviceAlarm();
 
     /** Reschedule the reset device alarm if needed */
     public abstract void rescheduleResetDeviceAlarmIfNeeded();
diff --git a/DeviceLockController/src/com/android/devicelockcontroller/DeviceLockControllerScheduler.java b/DeviceLockController/src/com/android/devicelockcontroller/DeviceLockControllerScheduler.java
index 59540e3..582b9af 100644
--- a/DeviceLockController/src/com/android/devicelockcontroller/DeviceLockControllerScheduler.java
+++ b/DeviceLockController/src/com/android/devicelockcontroller/DeviceLockControllerScheduler.java
@@ -244,7 +244,17 @@
     }
 
     @Override
-    public void scheduleResetDeviceAlarm(Duration delay) {
+    public void scheduleMandatoryResetDeviceAlarm() {
+        Duration delay = Duration.ofMinutes(RESET_DEVICE_IN_TWO_MINUTES);
+        if (Build.isDebuggable()) {
+            delay = Duration.ofMinutes(
+                    SystemProperties.getInt("devicelock.provision.reset-device-minutes",
+                            RESET_DEVICE_IN_TWO_MINUTES));
+        }
+        scheduleResetDeviceAlarm(delay);
+    }
+
+    private void scheduleResetDeviceAlarm(Duration delay) {
         scheduleResetDeviceAlarmInternal(delay);
         Instant whenExpectedToRun = Instant.now(mClock).plus(delay);
         DeviceLockNotificationManager.sendDeviceResetTimerNotification(mContext,
diff --git a/DeviceLockController/src/com/android/devicelockcontroller/activities/DeviceFinancingDeferredProvisionInfoViewModel.java b/DeviceLockController/src/com/android/devicelockcontroller/activities/DeviceFinancingDeferredProvisionInfoViewModel.java
deleted file mode 100644
index d7aae6a..0000000
--- a/DeviceLockController/src/com/android/devicelockcontroller/activities/DeviceFinancingDeferredProvisionInfoViewModel.java
+++ /dev/null
@@ -1,60 +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.devicelockcontroller.activities;
-
-import android.annotation.NonNull;
-import android.app.Application;
-
-import com.android.devicelockcontroller.R;
-
-import java.util.ArrayList;
-import java.util.List;
-
-
-/**
- * This class provides resources and data used for the deferred provisioning flow of the device
- * financing use case.
- */
-public final class DeviceFinancingDeferredProvisionInfoViewModel extends ProvisionInfoViewModel {
-
-    private static final int HEADER_DRAWABLE_ID = R.drawable.ic_info_24px;
-
-    private static final int HEADER_TEXT_ID = R.string.enroll_your_device_header;
-
-    private static final int SUBHEADER_TEXT_ID = R.string.enroll_your_device_financing_subheader;
-
-    private static final Integer[] DRAWABLE_IDS = new Integer[]{
-            R.drawable.ic_file_download_24px, R.drawable.ic_lock_outline_24px,
-    };
-
-    private static final Integer[] TEXT_IDS = new Integer[]{
-            R.string.download_kiosk_app, R.string.restrict_device_if_missing_payment,
-    };
-
-    public DeviceFinancingDeferredProvisionInfoViewModel(@NonNull Application application) {
-        super(application);
-
-        mHeaderDrawableId = HEADER_DRAWABLE_ID;
-        mHeaderTextId = HEADER_TEXT_ID;
-        mSubHeaderTextId = SUBHEADER_TEXT_ID;
-        List<ProvisionInfo> provisionInfoList = new ArrayList<>();
-        for (int i = 0, size = DRAWABLE_IDS.length; i < size; ++i) {
-            provisionInfoList.add(new ProvisionInfo(DRAWABLE_IDS[i], TEXT_IDS[i]));
-        }
-        mProvisionInfoList = provisionInfoList;
-    }
-}
diff --git a/DeviceLockController/src/com/android/devicelockcontroller/activities/DeviceFinancingProvisionInfoViewModel.java b/DeviceLockController/src/com/android/devicelockcontroller/activities/DeviceFinancingProvisionInfoViewModel.java
index fd53afe..52883e8 100644
--- a/DeviceLockController/src/com/android/devicelockcontroller/activities/DeviceFinancingProvisionInfoViewModel.java
+++ b/DeviceLockController/src/com/android/devicelockcontroller/activities/DeviceFinancingProvisionInfoViewModel.java
@@ -31,7 +31,7 @@
 
     private static final int HEADER_DRAWABLE_ID = R.drawable.ic_info_24px;
 
-    private static final int HEADER_TEXT_ID = R.string.device_provided_by_provider;
+    private static final int MANDATORY_HEADER_TEXT_ID = R.string.device_provided_by_provider;
 
     private static final Integer[] DRAWABLE_IDS = new Integer[]{
             R.drawable.ic_file_download_24px, R.drawable.ic_lock_outline_24px,
@@ -41,11 +41,18 @@
             R.string.download_kiosk_app, R.string.restrict_device_if_missing_payment,
     };
 
+    private static final int HEADER_TEXT_ID = R.string.enroll_your_device_header;
+
+    private static final int SUBHEADER_TEXT_ID =
+            R.string.enroll_your_device_financing_subheader;
+
     public DeviceFinancingProvisionInfoViewModel(@NonNull Application application) {
         super(application);
 
         mHeaderDrawableId = HEADER_DRAWABLE_ID;
+        mMandatoryHeaderTextId = MANDATORY_HEADER_TEXT_ID;
         mHeaderTextId = HEADER_TEXT_ID;
+        mSubHeaderTextId = SUBHEADER_TEXT_ID;
 
         List<ProvisionInfo> provisionInfoList = new ArrayList<>();
         for (int i = 0, size = DRAWABLE_IDS.length; i < size; ++i) {
diff --git a/DeviceLockController/src/com/android/devicelockcontroller/activities/DevicePoliciesFragment.java b/DeviceLockController/src/com/android/devicelockcontroller/activities/DevicePoliciesFragment.java
index 66f0039..783f9f3 100644
--- a/DeviceLockController/src/com/android/devicelockcontroller/activities/DevicePoliciesFragment.java
+++ b/DeviceLockController/src/com/android/devicelockcontroller/activities/DevicePoliciesFragment.java
@@ -92,8 +92,13 @@
                 new ViewModelProvider(requireActivity()).get(ProvisioningProgressViewModel.class);
         Button button = view.findViewById(R.id.button_next);
         checkNotNull(button);
-        button.setOnClickListener(
-                v -> provisionHelper.scheduleKioskAppInstallation(requireActivity(),
-                        provisioningProgressViewModel));
+        viewModel.getIsMandatoryLiveData().observe(this,
+                isMandatory -> {
+                    button.setOnClickListener(
+                            v -> provisionHelper.scheduleKioskAppInstallation(requireActivity(),
+                                    provisioningProgressViewModel,
+                                    isMandatory));
+                    button.setVisibility(View.VISIBLE);
+                });
     }
 }
diff --git a/DeviceLockController/src/com/android/devicelockcontroller/activities/DevicePoliciesViewModel.java b/DeviceLockController/src/com/android/devicelockcontroller/activities/DevicePoliciesViewModel.java
index 88ca681..03ccee4 100644
--- a/DeviceLockController/src/com/android/devicelockcontroller/activities/DevicePoliciesViewModel.java
+++ b/DeviceLockController/src/com/android/devicelockcontroller/activities/DevicePoliciesViewModel.java
@@ -16,6 +16,7 @@
 
 package com.android.devicelockcontroller.activities;
 
+import androidx.lifecycle.LiveData;
 import androidx.lifecycle.MediatorLiveData;
 import androidx.lifecycle.MutableLiveData;
 import androidx.lifecycle.ViewModel;
@@ -83,6 +84,12 @@
     final MutableLiveData<String> mProviderNameLiveData;
     final MediatorLiveData<List<DevicePolicyGroup>> mDevicePolicyGroupListLiveData;
 
+    public LiveData<Boolean> getIsMandatoryLiveData() {
+        return mIsMandatoryLiveData;
+    }
+
+    private final MutableLiveData<Boolean> mIsMandatoryLiveData = new MutableLiveData<>();
+
     public DevicePoliciesViewModel() {
         mProviderNameLiveData = new MutableLiveData<>();
         Futures.addCallback(SetupParametersClient.getInstance().getKioskAppProviderName(),
@@ -97,6 +104,19 @@
                         LogUtil.e(TAG, "Failed to get Device Provider name!", t);
                     }
                 }, MoreExecutors.directExecutor());
+
+        Futures.addCallback(SetupParametersClient.getInstance().isProvisionMandatory(),
+                new FutureCallback<>() {
+                    @Override
+                    public void onSuccess(Boolean result) {
+                        mIsMandatoryLiveData.postValue(result);
+                    }
+
+                    @Override
+                    public void onFailure(Throwable t) {
+                        LogUtil.e(TAG, "Failed to know if provision is mandatory!", t);
+                    }
+                }, MoreExecutors.directExecutor());
         mDevicePolicyGroupListLiveData = new MediatorLiveData<>();
         mDevicePolicyGroupListLiveData.addSource(mProviderNameLiveData,
                 unused -> mDevicePolicyGroupListLiveData.setValue(DEVICE_POLICY_GROUPS));
diff --git a/DeviceLockController/src/com/android/devicelockcontroller/activities/DeviceSubsidyDeferredProvisionInfoViewModel.java b/DeviceLockController/src/com/android/devicelockcontroller/activities/DeviceSubsidyDeferredProvisionInfoViewModel.java
deleted file mode 100644
index eb12e62..0000000
--- a/DeviceLockController/src/com/android/devicelockcontroller/activities/DeviceSubsidyDeferredProvisionInfoViewModel.java
+++ /dev/null
@@ -1,59 +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.devicelockcontroller.activities;
-
-import android.annotation.NonNull;
-import android.app.Application;
-
-import com.android.devicelockcontroller.R;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * This class provides resources and data used for the deferred provisioning flow of the device
- * subsidy use case.
- */
-public final class DeviceSubsidyDeferredProvisionInfoViewModel extends ProvisionInfoViewModel {
-
-    private static final int HEADER_DRAWABLE_ID = R.drawable.ic_info_24px;
-
-    private static final int HEADER_TEXT_ID = R.string.enroll_your_device_header;
-
-    private static final int SUBHEADER_TEXT_ID = R.string.enroll_your_device_subsidy_subheader;
-
-    private static final Integer[] DRAWABLE_IDS = new Integer[]{
-            R.drawable.ic_file_download_24px, R.drawable.ic_lock_outline_24px,
-    };
-
-    private static final Integer[] TEXT_IDS = new Integer[]{
-            R.string.download_kiosk_app, R.string.restrict_device_if_dont_make_payment,
-    };
-
-    public DeviceSubsidyDeferredProvisionInfoViewModel(@NonNull Application application) {
-        super(application);
-
-        mHeaderDrawableId = HEADER_DRAWABLE_ID;
-        mHeaderTextId = HEADER_TEXT_ID;
-        mSubHeaderTextId = SUBHEADER_TEXT_ID;
-        List<ProvisionInfo> provisionInfoList = new ArrayList<>();
-        for (int i = 0, size = DRAWABLE_IDS.length; i < size; ++i) {
-            provisionInfoList.add(new ProvisionInfo(DRAWABLE_IDS[i], TEXT_IDS[i]));
-        }
-        mProvisionInfoList = provisionInfoList;
-    }
-}
diff --git a/DeviceLockController/src/com/android/devicelockcontroller/activities/DeviceSubsidyProvisionInfoViewModel.java b/DeviceLockController/src/com/android/devicelockcontroller/activities/DeviceSubsidyProvisionInfoViewModel.java
index 66c49ed..0a91921 100644
--- a/DeviceLockController/src/com/android/devicelockcontroller/activities/DeviceSubsidyProvisionInfoViewModel.java
+++ b/DeviceLockController/src/com/android/devicelockcontroller/activities/DeviceSubsidyProvisionInfoViewModel.java
@@ -31,7 +31,7 @@
 
     private static final int HEADER_DRAWABLE_ID = R.drawable.ic_info_24px;
 
-    private static final int HEADER_TEXT_ID = R.string.subsidy_program_header;
+    private static final int MANDATORY_HEADER_TEXT_ID = R.string.subsidy_program_header;
 
     private static final Integer[] DRAWABLE_IDS = new Integer[]{
             R.drawable.ic_file_download_24px, R.drawable.ic_lock_outline_24px,
@@ -41,11 +41,17 @@
             R.string.download_kiosk_app, R.string.restrict_device_if_dont_make_payment,
     };
 
+    private static final int HEADER_TEXT_ID = R.string.enroll_your_device_header;
+
+    private static final int SUBHEADER_TEXT_ID = R.string.enroll_your_device_subsidy_subheader;
+
     public DeviceSubsidyProvisionInfoViewModel(@NonNull Application application) {
         super(application);
 
         mHeaderDrawableId = HEADER_DRAWABLE_ID;
+        mMandatoryHeaderTextId = MANDATORY_HEADER_TEXT_ID;
         mHeaderTextId = HEADER_TEXT_ID;
+        mSubHeaderTextId = SUBHEADER_TEXT_ID;
         List<ProvisionInfo> provisionInfoList = new ArrayList<>();
         for (int i = 0, size = DRAWABLE_IDS.length; i < size; ++i) {
             provisionInfoList.add(new ProvisionInfo(DRAWABLE_IDS[i], TEXT_IDS[i]));
diff --git a/DeviceLockController/src/com/android/devicelockcontroller/activities/LandingActivity.java b/DeviceLockController/src/com/android/devicelockcontroller/activities/LandingActivity.java
index 71acf35..2a59a49 100644
--- a/DeviceLockController/src/com/android/devicelockcontroller/activities/LandingActivity.java
+++ b/DeviceLockController/src/com/android/devicelockcontroller/activities/LandingActivity.java
@@ -22,7 +22,6 @@
 
 import androidx.annotation.Nullable;
 import androidx.appcompat.app.AppCompatActivity;
-import androidx.fragment.app.Fragment;
 
 import com.android.devicelockcontroller.R;
 
@@ -41,10 +40,9 @@
             controller.hide(WindowInsets.Type.systemBars());
         }
         if (savedInstanceState == null) {
-            Fragment fragment = new ProvisionInfoFragment();
             getSupportFragmentManager()
                     .beginTransaction()
-                    .add(R.id.fragment_container, fragment)
+                    .add(R.id.fragment_container, new ProvisionInfoFragment())
                     .commit();
         }
     }
diff --git a/DeviceLockController/src/com/android/devicelockcontroller/activities/ProgressFragment.java b/DeviceLockController/src/com/android/devicelockcontroller/activities/ProgressFragment.java
index 380ba2c..0eb21e7 100644
--- a/DeviceLockController/src/com/android/devicelockcontroller/activities/ProgressFragment.java
+++ b/DeviceLockController/src/com/android/devicelockcontroller/activities/ProgressFragment.java
@@ -109,7 +109,8 @@
                         retryButton.setOnClickListener(
                                 view -> provisionHelper.scheduleKioskAppInstallation(
                                         requireActivity(),
-                                        provisioningProgressViewModel));
+                                        provisioningProgressViewModel,
+                                        /* isProvisionMandatory= */ false));
 
                         Button exitButton = bottomView.findViewById(R.id.button_exit);
                         checkNotNull(exitButton);
diff --git a/DeviceLockController/src/com/android/devicelockcontroller/activities/ProvisionInfoFragment.java b/DeviceLockController/src/com/android/devicelockcontroller/activities/ProvisionInfoFragment.java
index c8fc26c..9ad7f36 100644
--- a/DeviceLockController/src/com/android/devicelockcontroller/activities/ProvisionInfoFragment.java
+++ b/DeviceLockController/src/com/android/devicelockcontroller/activities/ProvisionInfoFragment.java
@@ -16,10 +16,8 @@
 
 package com.android.devicelockcontroller.activities;
 
-import static com.android.devicelockcontroller.common.DeviceLockConstants.ACTION_START_DEVICE_FINANCING_DEFERRED_PROVISIONING;
 import static com.android.devicelockcontroller.common.DeviceLockConstants.ACTION_START_DEVICE_FINANCING_PROVISIONING;
 import static com.android.devicelockcontroller.common.DeviceLockConstants.ACTION_START_DEVICE_FINANCING_SECONDARY_USER_PROVISIONING;
-import static com.android.devicelockcontroller.common.DeviceLockConstants.ACTION_START_DEVICE_SUBSIDY_DEFERRED_PROVISIONING;
 import static com.android.devicelockcontroller.common.DeviceLockConstants.ACTION_START_DEVICE_SUBSIDY_PROVISIONING;
 
 import static com.google.common.base.Preconditions.checkNotNull;
@@ -75,29 +73,17 @@
     public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
         super.onViewCreated(view, savedInstanceState);
         ProvisionInfoViewModel viewModel;
-        boolean isDeferredProvisioning = false;
+        ViewModelProvider viewModelProvider = new ViewModelProvider(this);
         switch (Objects.requireNonNull(getActivity()).getIntent().getAction()) {
             case ACTION_START_DEVICE_FINANCING_PROVISIONING:
-                viewModel = new ViewModelProvider(this).get(
-                        DeviceFinancingProvisionInfoViewModel.class);
-                break;
-            case ACTION_START_DEVICE_FINANCING_DEFERRED_PROVISIONING:
-                viewModel = new ViewModelProvider(this).get(
-                        DeviceFinancingDeferredProvisionInfoViewModel.class);
-                isDeferredProvisioning = true;
+                viewModel = viewModelProvider.get(DeviceFinancingProvisionInfoViewModel.class);
                 break;
             case ACTION_START_DEVICE_FINANCING_SECONDARY_USER_PROVISIONING:
-                viewModel = new ViewModelProvider(this).get(
+                viewModel = viewModelProvider.get(
                         DeviceFinancingSecondaryUserProvisionInfoViewModel.class);
                 break;
             case ACTION_START_DEVICE_SUBSIDY_PROVISIONING:
-                viewModel = new ViewModelProvider(this).get(
-                        DeviceSubsidyProvisionInfoViewModel.class);
-                break;
-            case ACTION_START_DEVICE_SUBSIDY_DEFERRED_PROVISIONING:
-                viewModel = new ViewModelProvider(this).get(
-                        DeviceSubsidyDeferredProvisionInfoViewModel.class);
-                isDeferredProvisioning = true;
+                viewModel = viewModelProvider.get(DeviceSubsidyProvisionInfoViewModel.class);
                 break;
             default:
                 LogUtil.e(TAG, "Unknown action is received, exiting");
@@ -147,10 +133,15 @@
         Button next = view.findViewById(R.id.button_next);
         checkNotNull(next);
         Context context = requireContext().getApplicationContext();
-        if (isDeferredProvisioning) {
-            next.setText(R.string.start);
-            DeviceLockNotificationManager.cancelDeferredProvisioningNotification(context);
-        }
+        viewModel.mIsMandatoryLiveData.observe(this,
+                isMandatory -> {
+                    if (!isMandatory) {
+                        next.setText(R.string.start);
+                        DeviceLockNotificationManager.cancelDeferredProvisioningNotification(
+                                context);
+                    }
+                    next.setVisibility(View.VISIBLE);
+                });
         next.setOnClickListener(
                 v -> startActivity(new Intent(context, ProvisioningActivity.class)));
 
@@ -159,17 +150,19 @@
         mResultLauncher = registerForActivityResult(new ActivityResultContracts.RequestPermission(),
                 isGranted -> provisionHelper.pauseProvision());
         updatePreviousButton(checkNotNull(view.findViewById(R.id.button_previous)), viewModel,
-                isDeferredProvisioning, provisionHelper);
+                provisionHelper);
     }
 
     private void updatePreviousButton(Button previous, ProvisionInfoViewModel viewModel,
-            boolean isDeferredProvisioning, ProvisionHelper provisionHelper) {
-        if (!isDeferredProvisioning) {
-            previous.setVisibility(View.GONE);
-            return;
-        }
-        previous.setText(R.string.do_it_in_one_hour);
-        previous.setVisibility(View.VISIBLE);
+            ProvisionHelper provisionHelper) {
+        viewModel.mIsMandatoryLiveData.observe(this,
+                isMandatory -> {
+                    if (!isMandatory) {
+                        previous.setText(R.string.do_it_in_one_hour);
+                        previous.setVisibility(View.VISIBLE);
+                    }
+                });
+
 
         viewModel.mIsProvisionForcedLiveData.observe(getViewLifecycleOwner(),
                 isProvisionForced -> {
diff --git a/DeviceLockController/src/com/android/devicelockcontroller/activities/ProvisionInfoViewModel.java b/DeviceLockController/src/com/android/devicelockcontroller/activities/ProvisionInfoViewModel.java
index 3cffca3..8cb5bf0 100644
--- a/DeviceLockController/src/com/android/devicelockcontroller/activities/ProvisionInfoViewModel.java
+++ b/DeviceLockController/src/com/android/devicelockcontroller/activities/ProvisionInfoViewModel.java
@@ -44,14 +44,17 @@
 
     public static final String TAG = "ProvisionInfoViewModel";
     int mHeaderDrawableId;
+    int mMandatoryHeaderTextId;
     int mHeaderTextId;
+    int mMandatorySubHeaderTextId;
     int mSubHeaderTextId;
     List<ProvisionInfo> mProvisionInfoList;
+    final MutableLiveData<Boolean> mIsMandatoryLiveData = new MutableLiveData<>();
     final MutableLiveData<String> mProviderNameLiveData;
     final MutableLiveData<String> mTermsAndConditionsUrlLiveData;
     final MutableLiveData<Boolean> mIsProvisionForcedLiveData;
-    final MediatorLiveData<Pair<Integer, String>> mHeaderTextLiveData;
-    final MediatorLiveData<Pair<Integer, String>> mSubHeaderTextLiveData;
+    final MutableLiveData<Pair<Integer, String>> mHeaderTextLiveData = new MutableLiveData<>();
+    final MutableLiveData<Pair<Integer, String>> mSubHeaderTextLiveData = new MutableLiveData<>();
     final MediatorLiveData<List<ProvisionInfo>> mProvisionInfoListLiveData;
 
     public ProvisionInfoViewModel(@NonNull Application application) {
@@ -59,19 +62,12 @@
         mProviderNameLiveData = new MutableLiveData<>();
         mTermsAndConditionsUrlLiveData = new MutableLiveData<>();
         mIsProvisionForcedLiveData = new MutableLiveData<>();
-        mHeaderTextLiveData = new MediatorLiveData<>();
-        mHeaderTextLiveData.addSource(mProviderNameLiveData,
-                providerName -> mHeaderTextLiveData.setValue(
-                        new Pair<>(mHeaderTextId, providerName)));
-        mSubHeaderTextLiveData = new MediatorLiveData<>();
-        mSubHeaderTextLiveData.addSource(mProviderNameLiveData,
-                providerName -> mSubHeaderTextLiveData.setValue(
-                        new Pair<>(mSubHeaderTextId, providerName)));
         mProvisionInfoListLiveData = new MediatorLiveData<>();
 
         SetupParametersClient setupParametersClient = SetupParametersClient.getInstance();
         ListenableFuture<String> getKioskAppProviderNameFuture =
                 setupParametersClient.getKioskAppProviderName();
+        ListenableFuture<Boolean> isMandatoryFuture = setupParametersClient.isProvisionMandatory();
         ListenableFuture<String> getTermsAndConditionsUrlFuture =
                 setupParametersClient.getTermsAndConditionsUrl();
 
@@ -93,6 +89,31 @@
                     }
                 }, MoreExecutors.directExecutor());
 
+        Futures.whenAllSucceed(isMandatoryFuture, getKioskAppProviderNameFuture).call(
+                () -> {
+                    Boolean isMandatory = Futures.getDone(isMandatoryFuture);
+                    String kioskProviderName = Futures.getDone(getKioskAppProviderNameFuture);
+                    mHeaderTextLiveData.postValue(new Pair<>(
+                            isMandatory ? mMandatoryHeaderTextId : mHeaderTextId,
+                            kioskProviderName));
+                    mSubHeaderTextLiveData.postValue(new Pair<>(
+                            isMandatory ? mMandatorySubHeaderTextId : mSubHeaderTextId,
+                            kioskProviderName));
+                    return null;
+                }, MoreExecutors.directExecutor());
+        Futures.addCallback(isMandatoryFuture,
+                new FutureCallback<>() {
+                    @Override
+                    public void onSuccess(Boolean isMandatory) {
+                        mIsMandatoryLiveData.postValue(isMandatory);
+                    }
+
+                    @Override
+                    public void onFailure(Throwable t) {
+                        LogUtil.e(TAG, "Failed to know if provision is mandatory", t);
+                    }
+                }, MoreExecutors.directExecutor());
+
         Futures.addCallback(
                 getTermsAndConditionsUrlFuture,
                 new FutureCallback<>() {
diff --git a/DeviceLockController/src/com/android/devicelockcontroller/activities/ProvisioningProgress.java b/DeviceLockController/src/com/android/devicelockcontroller/activities/ProvisioningProgress.java
index e56028f..934b463 100644
--- a/DeviceLockController/src/com/android/devicelockcontroller/activities/ProvisioningProgress.java
+++ b/DeviceLockController/src/com/android/devicelockcontroller/activities/ProvisioningProgress.java
@@ -36,6 +36,11 @@
             R.string.click_to_contact_financier, /* progressBarVisible=*/ false,
             /* bottomViewVisible= */ true);
 
+    public static final ProvisioningProgress PROVISION_FAILED_MANDATORY = new ProvisioningProgress(
+            R.drawable.ic_warning_24px, R.string.provisioning_failed,
+            R.string.click_to_contact_financier, /* progressBarVisible=*/ false,
+            /* bottomViewVisible= */ false);
+
     final int mIconId;
     final int mHeaderId;
     final int mSubheaderId;
diff --git a/DeviceLockController/src/com/android/devicelockcontroller/common/DeviceLockConstants.java b/DeviceLockController/src/com/android/devicelockcontroller/common/DeviceLockConstants.java
index ef83b51..5b0ae67 100644
--- a/DeviceLockController/src/com/android/devicelockcontroller/common/DeviceLockConstants.java
+++ b/DeviceLockController/src/com/android/devicelockcontroller/common/DeviceLockConstants.java
@@ -16,8 +16,6 @@
 
 package com.android.devicelockcontroller.common;
 
-import android.content.Context;
-
 import androidx.annotation.IntDef;
 
 import java.lang.annotation.ElementType;
@@ -27,9 +25,6 @@
 
 /** Constants being used by more than one class in the Device Lock application. */
 public final class DeviceLockConstants {
-
-    public static final String KEY_KIOSK_APP_INSTALLED = "devicelock_kiosk_app_installed";
-
     // Constants related to unique device identifiers.
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(value = {
@@ -119,39 +114,14 @@
 
     public static final String ACTION_START_DEVICE_FINANCING_PROVISIONING =
             "com.android.devicelockcontroller.action.START_DEVICE_FINANCING_PROVISIONING";
-    public static final String ACTION_START_DEVICE_FINANCING_DEFERRED_PROVISIONING =
-            "com.android.devicelockcontroller.action.START_DEVICE_FINANCING_DEFERRED_PROVISIONING";
 
     public static final String ACTION_START_DEVICE_FINANCING_SECONDARY_USER_PROVISIONING =
             "com.android.devicelockcontroller.action"
-            + ".START_DEVICE_FINANCING_SECONDARY_USER_PROVISIONING";
+                    + ".START_DEVICE_FINANCING_SECONDARY_USER_PROVISIONING";
 
     public static final String ACTION_START_DEVICE_SUBSIDY_PROVISIONING =
             "com.android.devicelockcontroller.action.START_DEVICE_SUBSIDY_PROVISIONING";
 
-    public static final String ACTION_START_DEVICE_SUBSIDY_DEFERRED_PROVISIONING =
-            "com.android.devicelockcontroller.action.START_DEVICE_SUBSIDY_DEFERRED_PROVISIONING";
-
-    /** Uses the package name of {@link Context#getPackageName()} to return the landing activity. */
-    public static String getLandingActivity(Context context) {
-        return context.getPackageName() + "/"
-               + "com.android.devicelockcontroller.activities.LandingActivity";
-    }
-
-    /** Definitions for setup failure types. */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(
-            value = {
-                    SetupFailureReason.SETUP_FAILED,
-                    SetupFailureReason.INSTALL_FAILED,
-            })
-    public @interface SetupFailureReason {
-        /** Setup failed to complete */
-        int SETUP_FAILED = 0;
-        /** Failed to install the creditor apk. */
-        int INSTALL_FAILED = 1;
-    }
-
     /** Definitions for device provision states. */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(
diff --git a/DeviceLockController/src/com/android/devicelockcontroller/policy/DevicePolicyControllerImpl.java b/DeviceLockController/src/com/android/devicelockcontroller/policy/DevicePolicyControllerImpl.java
index 1c3c09b..4ab972f 100644
--- a/DeviceLockController/src/com/android/devicelockcontroller/policy/DevicePolicyControllerImpl.java
+++ b/DeviceLockController/src/com/android/devicelockcontroller/policy/DevicePolicyControllerImpl.java
@@ -16,9 +16,7 @@
 
 package com.android.devicelockcontroller.policy;
 
-import static com.android.devicelockcontroller.common.DeviceLockConstants.ACTION_START_DEVICE_FINANCING_DEFERRED_PROVISIONING;
 import static com.android.devicelockcontroller.common.DeviceLockConstants.ACTION_START_DEVICE_FINANCING_PROVISIONING;
-import static com.android.devicelockcontroller.common.DeviceLockConstants.ACTION_START_DEVICE_SUBSIDY_DEFERRED_PROVISIONING;
 import static com.android.devicelockcontroller.common.DeviceLockConstants.ACTION_START_DEVICE_SUBSIDY_PROVISIONING;
 import static com.android.devicelockcontroller.policy.DeviceStateController.DeviceState.CLEARED;
 import static com.android.devicelockcontroller.policy.DeviceStateController.DeviceState.LOCKED;
@@ -286,25 +284,19 @@
         SetupParametersClient client = SetupParametersClient.getInstance();
         ListenableFuture<@ProvisioningType Integer> provisioningType =
                 client.getProvisioningType();
-        ListenableFuture<Boolean> isMandatory = client.isProvisionMandatory();
-        return Futures.whenAllSucceed(provisioningType, isMandatory).call(
-                () -> {
+        return Futures.transform(provisioningType,
+                type -> {
                     Intent resultIntent = new Intent(mContext, LandingActivity.class);
-                    switch (Futures.getDone(provisioningType)) {
+                    switch (type) {
                         case ProvisioningType.TYPE_FINANCED:
                             // TODO(b/288923554) this used to return an intent with action
                             // ACTION_START_DEVICE_FINANCING_SECONDARY_USER_PROVISIONING
                             // for secondary users. Rework once a decision has been made about
                             // what to show to users.
                             return resultIntent.setAction(
-                                    Futures.getDone(isMandatory)
-                                            ? ACTION_START_DEVICE_FINANCING_PROVISIONING
-                                            : ACTION_START_DEVICE_FINANCING_DEFERRED_PROVISIONING);
+                                    ACTION_START_DEVICE_FINANCING_PROVISIONING);
                         case ProvisioningType.TYPE_SUBSIDY:
-                            return resultIntent.setAction(
-                                    Futures.getDone(isMandatory)
-                                            ? ACTION_START_DEVICE_SUBSIDY_PROVISIONING
-                                            : ACTION_START_DEVICE_SUBSIDY_DEFERRED_PROVISIONING);
+                            return resultIntent.setAction(ACTION_START_DEVICE_SUBSIDY_PROVISIONING);
                         case ProvisioningType.TYPE_UNDEFINED:
                         default:
                             throw new IllegalArgumentException("Provisioning type is unknown!");
diff --git a/DeviceLockController/src/com/android/devicelockcontroller/policy/ProvisionHelper.java b/DeviceLockController/src/com/android/devicelockcontroller/policy/ProvisionHelper.java
index 0adaa62..3d51559 100644
--- a/DeviceLockController/src/com/android/devicelockcontroller/policy/ProvisionHelper.java
+++ b/DeviceLockController/src/com/android/devicelockcontroller/policy/ProvisionHelper.java
@@ -33,5 +33,6 @@
      * Start installation and open kiosk when it finish.
      */
     void scheduleKioskAppInstallation(LifecycleOwner owner,
-            ProvisioningProgressController progressController);
+            ProvisioningProgressController progressController,
+            boolean isProvisionMandatory);
 }
diff --git a/DeviceLockController/src/com/android/devicelockcontroller/policy/ProvisionHelperImpl.java b/DeviceLockController/src/com/android/devicelockcontroller/policy/ProvisionHelperImpl.java
index 1234983..70a6d36 100644
--- a/DeviceLockController/src/com/android/devicelockcontroller/policy/ProvisionHelperImpl.java
+++ b/DeviceLockController/src/com/android/devicelockcontroller/policy/ProvisionHelperImpl.java
@@ -101,7 +101,7 @@
 
     @Override
     public void scheduleKioskAppInstallation(LifecycleOwner owner,
-            ProvisioningProgressController progressController) {
+            ProvisioningProgressController progressController, boolean isMandatory) {
         LogUtil.v(TAG, "Trigger setup flow");
         progressController.setProvisioningProgress(ProvisioningProgress.GETTING_DEVICE_READY);
         Futures.addCallback(SetupParametersClient.getInstance().getKioskPackage(),
@@ -168,8 +168,15 @@
                     @Override
                     public void onFailure(Throwable t) {
                         LogUtil.w(TAG, "Failed to install kiosk app!", t);
-                        progressController.setProvisioningProgress(
-                                ProvisioningProgress.PROVISIONING_FAILED);
+                        if (isMandatory) {
+                            progressController.setProvisioningProgress(
+                                    ProvisioningProgress.PROVISION_FAILED_MANDATORY);
+                            new DeviceLockControllerScheduler(
+                                    mContext).scheduleMandatoryResetDeviceAlarm();
+                        } else {
+                            progressController.setProvisioningProgress(
+                                    ProvisioningProgress.PROVISIONING_FAILED);
+                        }
                     }
                 }, sExecutor);
     }
diff --git a/DeviceLockController/src/com/android/devicelockcontroller/policy/ProvisionStateControllerImpl.java b/DeviceLockController/src/com/android/devicelockcontroller/policy/ProvisionStateControllerImpl.java
index 849df9e..53551da 100644
--- a/DeviceLockController/src/com/android/devicelockcontroller/policy/ProvisionStateControllerImpl.java
+++ b/DeviceLockController/src/com/android/devicelockcontroller/policy/ProvisionStateControllerImpl.java
@@ -39,8 +39,6 @@
 import androidx.annotation.VisibleForTesting;
 import androidx.work.WorkManager;
 
-import com.android.devicelockcontroller.AbstractDeviceLockControllerScheduler;
-import com.android.devicelockcontroller.DeviceLockControllerScheduler;
 import com.android.devicelockcontroller.provision.worker.ReportDeviceProvisionStateWorker;
 import com.android.devicelockcontroller.receivers.LockedBootCompletedReceiver;
 import com.android.devicelockcontroller.storage.GlobalParametersClient;
@@ -68,7 +66,6 @@
     private final DevicePolicyController mPolicyController;
     private final DeviceStateController mDeviceStateController;
     private final Executor mBgExecutor;
-    private AbstractDeviceLockControllerScheduler mScheduler;
 
     @GuardedBy("this")
     private ListenableFuture<@ProvisionState Integer> mCurrentStateFuture;
@@ -162,10 +159,6 @@
         } else if (state == PROVISION_FAILED) {
             ReportDeviceProvisionStateWorker.reportSetupFailed(
                     WorkManager.getInstance(mContext));
-            if (mScheduler == null) {
-                mScheduler = new DeviceLockControllerScheduler(mContext);
-            }
-            mScheduler.scheduleNextProvisionFailedStepAlarm();
         } else if (state == PROVISION_IN_PROGRESS) {
             mContext.getPackageManager().setComponentEnabledSetting(
                     new ComponentName(mContext, LockedBootCompletedReceiver.class),
diff --git a/DeviceLockController/tests/robolectric/src/com/android/devicelockcontroller/policy/ProvisionHelperImplTest.java b/DeviceLockController/tests/robolectric/src/com/android/devicelockcontroller/policy/ProvisionHelperImplTest.java
index 3300cf8..cd7183d 100644
--- a/DeviceLockController/tests/robolectric/src/com/android/devicelockcontroller/policy/ProvisionHelperImplTest.java
+++ b/DeviceLockController/tests/robolectric/src/com/android/devicelockcontroller/policy/ProvisionHelperImplTest.java
@@ -125,8 +125,8 @@
         kioskPackageInfo.packageName = TEST_PACKAGE_NAME;
         pm.installPackage(kioskPackageInfo);
         setupLifecycle();
-
-        mProvisionHelper.scheduleKioskAppInstallation(mMockLifecycleOwner, mProgressController);
+        mProvisionHelper.scheduleKioskAppInstallation(mMockLifecycleOwner,
+                mProgressController, /* isProvisionMandatory= */ false);
 
         ArgumentCaptor<ProvisioningProgress> argumentCaptor = ArgumentCaptor.forClass(
                 ProvisioningProgress.class);