• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2016, The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.managedprovisioning.preprovisioning;
18 
19 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_TRIGGER;
20 import static android.app.admin.DevicePolicyManager.EXTRA_RESULT_LAUNCH_INTENT;
21 import static android.app.admin.DevicePolicyManager.EXTRA_ROLE_HOLDER_UPDATE_FAILURE_STRATEGY;
22 import static android.app.admin.DevicePolicyManager.EXTRA_ROLE_HOLDER_UPDATE_RESULT_CODE;
23 import static android.app.admin.DevicePolicyManager.PROVISIONING_TRIGGER_UNSPECIFIED;
24 import static android.app.admin.DevicePolicyManager.RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_PROVISIONING_DISABLED;
25 import static android.app.admin.DevicePolicyManager.RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_RECOVERABLE_ERROR;
26 import static android.app.admin.DevicePolicyManager.RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_UNRECOVERABLE_ERROR;
27 import static android.app.admin.DevicePolicyManager.RESULT_UPDATE_ROLE_HOLDER;
28 import static android.app.admin.DevicePolicyManager.ROLE_HOLDER_UPDATE_FAILURE_STRATEGY_FAIL_PROVISIONING;
29 import static android.app.admin.DevicePolicyManager.ROLE_HOLDER_UPDATE_FAILURE_STRATEGY_FALLBACK_TO_PLATFORM_PROVISIONING;
30 import static android.content.res.Configuration.UI_MODE_NIGHT_MASK;
31 import static android.content.res.Configuration.UI_MODE_NIGHT_YES;
32 
33 import static com.android.managedprovisioning.ManagedProvisioningScreens.RETRY_LAUNCH;
34 import static com.android.managedprovisioning.common.ErrorDialogUtils.EXTRA_DIALOG_TITLE_ID;
35 import static com.android.managedprovisioning.common.ErrorDialogUtils.EXTRA_ERROR_MESSAGE_RES_ID;
36 import static com.android.managedprovisioning.common.ErrorDialogUtils.EXTRA_FACTORY_RESET_REQUIRED;
37 import static com.android.managedprovisioning.common.RetryLaunchActivity.EXTRA_INTENT_TO_LAUNCH;
38 import static com.android.managedprovisioning.model.ProvisioningParams.FLOW_TYPE_LEGACY;
39 import static com.android.managedprovisioning.preprovisioning.PreProvisioningViewModel.STATE_PREPROVISIONING_INITIALIZING;
40 import static com.android.managedprovisioning.preprovisioning.PreProvisioningViewModel.STATE_SHOWING_USER_CONSENT;
41 import static com.android.managedprovisioning.provisioning.Constants.PROVISIONING_SERVICE_INTENT;
42 
43 import static com.google.android.setupcompat.util.WizardManagerHelper.EXTRA_IS_SETUP_FLOW;
44 
45 import static java.util.Objects.requireNonNull;
46 
47 import android.annotation.NonNull;
48 import android.annotation.Nullable;
49 import android.app.Activity;
50 import android.app.BackgroundServiceStartNotAllowedException;
51 import android.app.DialogFragment;
52 import android.app.admin.DevicePolicyManager;
53 import android.content.Intent;
54 import android.os.Bundle;
55 import android.os.PersistableBundle;
56 import android.provider.Settings;
57 import android.text.TextUtils;
58 import android.view.ContextMenu;
59 import android.view.ContextMenu.ContextMenuInfo;
60 import android.view.View;
61 import android.widget.TextView;
62 
63 import androidx.annotation.VisibleForTesting;
64 
65 import com.android.managedprovisioning.ManagedProvisioningBaseApplication;
66 import com.android.managedprovisioning.ManagedProvisioningScreens;
67 import com.android.managedprovisioning.R;
68 import com.android.managedprovisioning.analytics.MetricsWriterFactory;
69 import com.android.managedprovisioning.analytics.ProvisioningAnalyticsTracker;
70 import com.android.managedprovisioning.common.AccessibilityContextMenuMaker;
71 import com.android.managedprovisioning.common.DefaultFeatureFlagChecker;
72 import com.android.managedprovisioning.common.DefaultIntentResolverChecker;
73 import com.android.managedprovisioning.common.DefaultPackageInstallChecker;
74 import com.android.managedprovisioning.common.DeviceManagementRoleHolderUpdaterHelper;
75 import com.android.managedprovisioning.common.GetProvisioningModeUtils;
76 import com.android.managedprovisioning.common.ManagedProvisioningSharedPreferences;
77 import com.android.managedprovisioning.common.ProvisionLogger;
78 import com.android.managedprovisioning.common.RetryLaunchActivity;
79 import com.android.managedprovisioning.common.RoleHolderProvider;
80 import com.android.managedprovisioning.common.RoleHolderUpdaterProvider;
81 import com.android.managedprovisioning.common.SettingsFacade;
82 import com.android.managedprovisioning.common.SetupGlifLayoutActivity;
83 import com.android.managedprovisioning.common.SimpleDialog;
84 import com.android.managedprovisioning.common.ThemeHelper;
85 import com.android.managedprovisioning.common.ThemeHelper.DefaultNightModeChecker;
86 import com.android.managedprovisioning.common.ThemeHelper.DefaultSetupWizardBridge;
87 import com.android.managedprovisioning.common.Utils;
88 import com.android.managedprovisioning.model.ProvisioningParams;
89 import com.android.managedprovisioning.preprovisioning.PreProvisioningActivityController.UiParams;
90 import com.android.managedprovisioning.provisioning.AdminIntegratedFlowPrepareActivity;
91 import com.android.managedprovisioning.provisioning.ProvisioningActivity;
92 import com.android.managedprovisioning.util.LazyStringResource;
93 
94 import com.google.android.setupcompat.logging.ScreenKey;
95 import com.google.android.setupcompat.logging.SetupMetric;
96 import com.google.android.setupcompat.logging.SetupMetricsLogger;
97 import com.google.android.setupcompat.util.WizardManagerHelper;
98 import com.google.android.setupdesign.transition.TransitionHelper;
99 
100 public class PreProvisioningActivity extends SetupGlifLayoutActivity implements
101         SimpleDialog.SimpleDialogListener, PreProvisioningActivityController.Ui {
102 
103     private static final int ENCRYPT_DEVICE_REQUEST_CODE = 1;
104     @VisibleForTesting
105     protected static final int PROVISIONING_REQUEST_CODE = 2;
106     private static final int WIFI_REQUEST_CODE = 3;
107     private static final int CHANGE_LAUNCHER_REQUEST_CODE = 4;
108     private static final int ORGANIZATION_OWNED_LANDING_PAGE_REQUEST_CODE = 5;
109     private static final int GET_PROVISIONING_MODE_REQUEST_CODE = 6;
110     private static final int FINANCED_DEVICE_PREPARE_REQUEST_CODE = 7;
111     private static final int ADMIN_INTEGRATED_FLOW_PREPARE_REQUEST_CODE = 8;
112     private static final int START_PLATFORM_REQUESTED_ROLE_HOLDER_UPDATE_REQUEST_CODE = 9;
113     private static final int START_DEVICE_MANAGEMENT_ROLE_HOLDER_PROVISIONING_REQUEST_CODE = 10;
114     private static final int DOWNLOAD_DEVICE_MANAGEMENT_ROLE_HOLDER_FROM_PLATFORM_REQUEST_CODE = 11;
115     private static final int START_ROLE_HOLDER_REQUESTED_UPDATE_REQUEST_CODE = 12;
116 
117     // Note: must match the constant defined in HomeSettings
118     private static final String EXTRA_SUPPORT_MANAGED_PROFILES = "support_managed_profiles";
119 
120     private static final String ERROR_AND_CLOSE_DIALOG = "PreProvErrorAndCloseDialog";
121     private static final String BACK_PRESSED_DIALOG_RESET = "PreProvBackPressedDialogReset";
122     private static final String BACK_PRESSED_DIALOG_CLOSE_ACTIVITY =
123             "PreProvBackPressedDialogCloseActivity";
124     private static final String LAUNCHER_INVALID_DIALOG = "PreProvCurrentLauncherInvalidDialog";
125     private static final String SETUP_METRIC_PREPROVISIONING_SCREEN_NAME =
126             "ShowPreProvisioningScreen";
127 
128     private PreProvisioningActivityController mController;
129     private ControllerProvider mControllerProvider;
130     private final AccessibilityContextMenuMaker mContextMenuMaker;
131     private PreProvisioningActivityBridge mBridge;
132     private boolean mShouldForwardTransition;
133     private final RoleHolderUpdaterProvider mRoleHolderUpdaterProvider;
134     private final RoleHolderProvider mRoleHolderProvider;
135 
136     private static final String ERROR_DIALOG_RESET = "ErrorDialogReset";
137     private static final int SETUP_METRIC_DEFAULT_ERROR_CODE = -1;
138     private ProvisioningAnalyticsTracker mAnalyticsTracker;
139     private boolean mAlreadyInitialized;
140     protected ScreenKey mScreenKey;
141     protected String setupMetricScreenName;
142 
PreProvisioningActivity()143     public PreProvisioningActivity() {
144         this(activity ->
145                 new PreProvisioningActivityController(activity, activity),
146                 null,
147                 new Utils(),
148                 new SettingsFacade(),
149                 new ThemeHelper(
150                     new DefaultNightModeChecker(),
151                     new DefaultSetupWizardBridge()),
152                 RoleHolderProvider.DEFAULT,
153                 RoleHolderUpdaterProvider.DEFAULT);
154     }
155 
156     @VisibleForTesting
PreProvisioningActivity( ControllerProvider controllerProvider, AccessibilityContextMenuMaker contextMenuMaker, Utils utils, SettingsFacade settingsFacade, ThemeHelper themeHelper, RoleHolderProvider roleHolderProvider, RoleHolderUpdaterProvider roleHolderUpdaterProvider)157     public PreProvisioningActivity(
158             ControllerProvider controllerProvider,
159             AccessibilityContextMenuMaker contextMenuMaker, Utils utils,
160             SettingsFacade settingsFacade, ThemeHelper themeHelper,
161             RoleHolderProvider roleHolderProvider,
162             RoleHolderUpdaterProvider roleHolderUpdaterProvider) {
163         super(utils, settingsFacade, themeHelper);
164         mControllerProvider = requireNonNull(controllerProvider);
165         mContextMenuMaker =
166                 contextMenuMaker != null ? contextMenuMaker : new AccessibilityContextMenuMaker(
167                         this);
168         mRoleHolderUpdaterProvider = requireNonNull(roleHolderUpdaterProvider);
169         mRoleHolderProvider = requireNonNull(roleHolderProvider);
170     }
171 
172     @Override
onCreate(Bundle savedInstanceState)173     protected void onCreate(Bundle savedInstanceState) {
174         // TODO(b/192074477): Remove deferred setup-specific logic after the managed account flow
175         //  starts ManagedProvisioning with the isSetupFlow extra
176         // This temporary fix only works when called before super.onCreate
177         if (mSettingsFacade.isDeferredSetup(getApplicationContext())) {
178             getIntent().putExtra(EXTRA_IS_SETUP_FLOW, true);
179         }
180 
181         super.onCreate(savedInstanceState);
182         setupMetricScreenName = SETUP_METRIC_PREPROVISIONING_SCREEN_NAME;
183         mScreenKey = ScreenKey.of(setupMetricScreenName, this);
184 
185         if (savedInstanceState == null) {
186             mAlreadyInitialized = false;
187         }
188         mController = mControllerProvider.getInstance(this);
189         mBridge = createBridge();
190         mController.getState().observe(this, this::onStateChanged);
191 
192         mAnalyticsTracker =
193                 new ProvisioningAnalyticsTracker(
194                         MetricsWriterFactory.getMetricsWriter(this, new SettingsFacade()),
195                         new ManagedProvisioningSharedPreferences(this));
196         logMetrics();
197     }
198 
199     @Override
onStart()200     protected void onStart() {
201         super.onStart();
202         try {
203             getApplicationContext().startService(PROVISIONING_SERVICE_INTENT);
204         } catch (BackgroundServiceStartNotAllowedException e) {
205             ProvisionLogger.loge(e);
206         }
207         mController.getState().observe(this, this::onStateChanged);
208     }
209 
210     @Override
onResume()211     protected void onResume() {
212         super.onResume();
213         SetupMetricsLogger.logMetrics(this, mScreenKey,
214                 SetupMetric.ofImpression(setupMetricScreenName));
215         if (mShouldForwardTransition) {
216             TransitionHelper.applyForwardTransition(
217                     this, TransitionHelper.TRANSITION_FADE_THROUGH);
218             mShouldForwardTransition = false;
219         }
220     }
221 
createBridge()222     protected PreProvisioningActivityBridge createBridge() {
223         return new PreProvisioningActivityBridgeImpl(
224                 /* activity= */ this,
225                 mUtils,
226                 PreProvisioningActivity.this::initializeLayoutParams,
227                 createBridgeCallbacks(),
228                 getThemeHelper(),
229                 setupMetricScreenName);
230     }
231 
createBridgeCallbacks()232     protected final PreProvisioningActivityBridgeCallbacks createBridgeCallbacks() {
233         return new PreProvisioningActivityBridgeCallbacks() {
234             @Override
235             public void onTermsAccepted() {
236                 mController.continueProvisioningAfterUserConsent();
237             }
238 
239             @Override
240             public void onTermsButtonClicked() {
241                 getTransitionHelper()
242                         .startActivityWithTransition(PreProvisioningActivity.this,
243                                 mController.createViewTermsIntent());
244             }
245         };
246     }
247 
248     private void onStateChanged(Integer state) {
249         switch (state) {
250             case STATE_PREPROVISIONING_INITIALIZING:
251                 if (!mAlreadyInitialized) {
252                     mController.initiateProvisioning(getIntent(), getCallingPackage());
253                     mAlreadyInitialized = true;
254                 }
255                 break;
256             case STATE_SHOWING_USER_CONSENT:
257                 mController.showUserConsentScreen();
258                 break;
259         }
260     }
261 
262     @Override
263     public void finish() {
264         // The user has backed out of provisioning, so we perform the necessary clean up steps.
265         ProvisioningParams params = mController.getParams();
266         if (params != null) {
267             params.cleanUp();
268         }
269         getEncryptionController().cancelEncryptionReminder();
270         getApplicationContext().stopService(PROVISIONING_SERVICE_INTENT);
271         super.finish();
272     }
273 
274     @SuppressWarnings("MissingSuperCall") // TODO: Fix me
275     @Override
276     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
277         switch (requestCode) {
278             case ENCRYPT_DEVICE_REQUEST_CODE:
279                 if (resultCode == RESULT_CANCELED) {
280                     ProvisionLogger.loge("User canceled device encryption.");
281                 }
282                 break;
283             case PROVISIONING_REQUEST_CODE:
284                 mController.onReturnFromProvisioning();
285                 setResult(resultCode);
286                 getTransitionHelper().finishActivity(this);
287                 break;
288             case CHANGE_LAUNCHER_REQUEST_CODE:
289                 mController.continueProvisioningAfterUserConsent();
290                 break;
291             case WIFI_REQUEST_CODE:
292                 if (resultCode == RESULT_CANCELED) {
293                     ProvisionLogger.loge("User canceled wifi picking.");
294                     setResult(resultCode);
295                     getTransitionHelper().finishActivity(this);
296                 } else {
297                     if (resultCode == RESULT_OK) {
298                         ProvisionLogger.logd("Wifi request result is OK");
299                     }
300                     mController.initiateProvisioning(getIntent(), getCallingPackage());
301                 }
302                 break;
303             case ORGANIZATION_OWNED_LANDING_PAGE_REQUEST_CODE:
304             case ADMIN_INTEGRATED_FLOW_PREPARE_REQUEST_CODE:
305                 if (resultCode == RESULT_OK) {
306                     handleAdminIntegratedFlowPreparerResult();
307                 } else {
308                     ProvisionLogger.loge(
309                             "Provisioning was aborted in the preparation stage, "
310                                     + "requestCode = " + requestCode);
311                     SetupMetricsLogger.logMetrics(this, mScreenKey,
312                             SetupMetric.ofError(setupMetricScreenName, resultCode));
313                     if (isDpcInstalled()
314                             && mUtils.isOrganizationOwnedAllowed(mController.getParams())) {
315                         showFactoryResetDialog(R.string.cant_set_up_device,
316                                 R.string.contact_your_admin_for_help);
317                     } else {
318                         showErrorAndClose(
319                                 R.string.cant_set_up_device,
320                                 R.string.contact_your_admin_for_help,
321                                 "Failed provisioning device.");
322                     }
323                 }
324                 break;
325             case GET_PROVISIONING_MODE_REQUEST_CODE:
326                 mShouldForwardTransition = true;
327                 if (resultCode == RESULT_OK) {
328                     if(data != null && mController.updateProvisioningParamsFromIntent(data)) {
329                         mController.showUserConsentScreen();
330                     } else {
331                         ProvisionLogger.loge(
332                                 "Invalid data object returned from GET_PROVISIONING_MODE.");
333                         SetupMetricsLogger.logMetrics(this, mScreenKey,
334                                 SetupMetric.ofError(setupMetricScreenName, resultCode));
335                         if (mUtils.isOrganizationOwnedAllowed(mController.getParams())) {
336                             showFactoryResetDialog(R.string.cant_set_up_device,
337                                     R.string.contact_your_admin_for_help);
338                         } else {
339                             showErrorAndClose(
340                                     R.string.cant_set_up_device,
341                                     R.string.contact_your_admin_for_help,
342                                     "Failed provisioning personally-owned device.");
343                         }
344                     }
345                 } else {
346                     ProvisionLogger.loge("Invalid result code from GET_PROVISIONING_MODE. Expected "
347                             + RESULT_OK + " but got " + resultCode + ".");
348                     SetupMetricsLogger.logMetrics(this, mScreenKey,
349                             SetupMetric.ofError(setupMetricScreenName, resultCode));
350                     if (mUtils.isOrganizationOwnedAllowed(mController.getParams())) {
351                         showFactoryResetDialog(R.string.cant_set_up_device,
352                                 R.string.contact_your_admin_for_help);
353                     } else {
354                         showErrorAndClose(
355                                 R.string.cant_set_up_device,
356                                 R.string.contact_your_admin_for_help,
357                                 "Failed to provision personally-owned device.");
358                     }
359                 }
360                 break;
361             case FINANCED_DEVICE_PREPARE_REQUEST_CODE:
362                 if (resultCode == RESULT_OK) {
363                     startFinancedDeviceFlow();
364                 } else {
365                     setResult(resultCode);
366                     getTransitionHelper().finishActivity(this);
367                 }
368                 break;
369             case START_PLATFORM_REQUESTED_ROLE_HOLDER_UPDATE_REQUEST_CODE:
370                 handlePlatformRequestedUpdateResult(resultCode, data);
371                 break;
372             case START_ROLE_HOLDER_REQUESTED_UPDATE_REQUEST_CODE:
373                 handleRoleHolderRequestedUpdateResult(resultCode, data);
374                 break;
375             case START_DEVICE_MANAGEMENT_ROLE_HOLDER_PROVISIONING_REQUEST_CODE:
376                 ProvisionLogger.logw("Role holder returned result code " + resultCode);
377                 mAnalyticsTracker.logRoleHolderProvisioningFinish();
378                 if (resultCode == RESULT_UPDATE_ROLE_HOLDER) {
379                     if (handleUpdateRequestedWithNoRoleHolderUpdater(resultCode)) {
380                         return;
381                     }
382                     if (handleUpdateRequestedWithWrongStateType(data)) {
383                         return;
384                     }
385                     PersistableBundle roleHolderState =
386                             data.getParcelableExtra(DevicePolicyManager.EXTRA_ROLE_HOLDER_STATE);
387                     mController.resetRoleHolderUpdateRetryCount();
388                     mController.startRoleHolderUpdater(
389                             /* isRoleHolderRequestedUpdate= */ true, roleHolderState);
390                 } else {
391                     maybeHandleLaunchIntent(resultCode, data);
392                     getTransitionHelper().finishActivity(this);
393                 }
394                 break;
395             case DOWNLOAD_DEVICE_MANAGEMENT_ROLE_HOLDER_FROM_PLATFORM_REQUEST_CODE:
396                 mAnalyticsTracker.logPlatformRoleHolderUpdateFinished(resultCode);
397                 if (resultCode == RESULT_OK
398                         || mController.getParams().allowOffline) {
399                     boolean isProvisioningStarted = mController.startAppropriateProvisioning(
400                             getIntent(),
401                             new Bundle(),
402                             getCallingPackage());
403                     if (!isProvisioningStarted) {
404                         mAnalyticsTracker.logPlatformRoleHolderUpdateFailed();
405                         ProvisionLogger.loge("Provisioning could not be started following "
406                                 + "platform-side role holder download.");
407                         SetupMetricsLogger.logMetrics(this, mScreenKey,
408                                 SetupMetric.ofError(setupMetricScreenName, resultCode));
409                         showRoleHolderDownloadFailedDialog(new Intent());
410                     }
411                 } else if (data != null && data.hasExtra(EXTRA_ERROR_MESSAGE_RES_ID)) {
412                     mAnalyticsTracker.logPlatformRoleHolderUpdateFailed();
413                     ProvisionLogger.loge("Role holder download failed and offline provisioning is "
414                             + "not allowed.");
415                     SetupMetricsLogger.logMetrics(this, mScreenKey,
416                             SetupMetric.ofError(setupMetricScreenName, resultCode));
417                     showRoleHolderDownloadFailedDialog(data);
418                 } else {
419                     mAnalyticsTracker.logPlatformRoleHolderUpdateFailed();
420                     ProvisionLogger.loge("Role holder download failed and offline provisioning is "
421                             + "not allowed.");
422                     SetupMetricsLogger.logMetrics(this, mScreenKey,
423                             SetupMetric.ofError(setupMetricScreenName, resultCode));
424                     showRoleHolderDownloadFailedDialog(new Intent());
425                 }
426                 break;
427             default:
428                 ProvisionLogger.logw("Unknown result code :" + resultCode);
429                 SetupMetricsLogger.logMetrics(this, mScreenKey,
430                         SetupMetric.ofError(setupMetricScreenName, resultCode));
431                 break;
432         }
433     }
434 
435     private boolean handleUpdateRequestedWithWrongStateType(Intent data) {
436         if (!(data.getParcelableExtra(DevicePolicyManager.EXTRA_ROLE_HOLDER_STATE)
437                 instanceof PersistableBundle)) {
438             ProvisionLogger.loge("Failed to process role holder state result.");
439             SetupMetricsLogger.logMetrics(this, mScreenKey,
440                     SetupMetric.ofError(setupMetricScreenName, SETUP_METRIC_DEFAULT_ERROR_CODE));
441             if (mUtils.isOrganizationOwnedAllowed(mController.getParams())) {
442                 showFactoryResetDialog(R.string.cant_set_up_device,
443                         R.string.contact_your_admin_for_help);
444             } else {
445                 showErrorAndClose(
446                         R.string.cant_set_up_device,
447                         R.string.contact_your_admin_for_help,
448                         "Failed to process role holder state result.");
449             }
450             return true;
451         }
452         return false;
453     }
454 
455     private boolean handleUpdateRequestedWithNoRoleHolderUpdater(int resultCode) {
456         if (TextUtils.isEmpty(
457                 mRoleHolderUpdaterProvider.getPackageName(this))) {
458             ProvisionLogger.logw("Role holder requested update, but there is no role "
459                             + "holder updater present. Restarting the role holder.");
460             boolean isProvisioningStarted = mController.startAppropriateProvisioning(
461                     getIntent(),
462                     createRoleHolderAdditionalExtras(resultCode),
463                     getCallingPackage());
464             if (!isProvisioningStarted) {
465                 failRoleHolderUpdate();
466                 ProvisionLogger.loge("Failed to start provisioning after a "
467                         + "role holder-requested role holder update and no updater "
468                         + "present. Result is " + resultCode + " and allow offline "
469                         + "provisioning is " + mController.getParams().allowOffline);
470                 SetupMetricsLogger.logMetrics(this, mScreenKey,
471                         SetupMetric.ofError(setupMetricScreenName, resultCode));
472             }
473             return true;
474         }
475         return false;
476     }
477 
478     private Bundle createRoleHolderAdditionalExtras(int resultCode) {
479         Bundle additionalExtras = new Bundle();
480         additionalExtras.putInt(EXTRA_ROLE_HOLDER_UPDATE_RESULT_CODE, resultCode);
481         return additionalExtras;
482     }
483 
484     private void handlePlatformRequestedUpdateResult(int resultCode, @Nullable Intent resultData) {
485         mAnalyticsTracker.logRoleHolderUpdaterUpdateFinish(resultCode);
486         if ((resultCode
487                 == RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_RECOVERABLE_ERROR
488                 || resultCode == RESULT_CANCELED)
489                 && mController.canRetryRoleHolderUpdate()) {
490             mController.startRoleHolderUpdaterWithLastState(
491                     /* isRoleHolderRequestedUpdate= */ false);
492             mController.incrementRoleHolderUpdateRetryCount();
493             mAnalyticsTracker.logRoleHolderUpdaterUpdateRetry();
494         } else if (resultCode
495                 == RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_PROVISIONING_DISABLED
496         ) {
497             mController.performPlatformProvidedProvisioning();
498         } else if (resultCode
499                 != RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_UNRECOVERABLE_ERROR) {
500             mController.resetRoleHolderUpdateRetryCount();
501             boolean isProvisioningStarted = mController.startAppropriateProvisioning(
502                     getIntent(),
503                     createRoleHolderAdditionalExtras(resultCode),
504                     getCallingPackage());
505             if (!isProvisioningStarted) {
506                 if (isRoleHolderUpdaterRequestingPlatformDrivenProvisioning(resultData)) {
507                     ProvisionLogger.logi("Result is " + resultCode
508                             + " and applied fallback strategy.");
509                     mController.performPlatformProvidedProvisioning();
510                 } else {
511                     mAnalyticsTracker.logRoleHolderUpdaterUpdateFailed();
512                     failRoleHolderUpdate();
513                     ProvisionLogger.loge("Failed to start provisioning after a "
514                         + "platform-requested role holder update. Result is " + resultCode
515                         + " and allow offline provisioning is "
516                         + mController.getParams().allowOffline);
517                     SetupMetricsLogger.logMetrics(this, mScreenKey,
518                             SetupMetric.ofError(setupMetricScreenName, resultCode));
519                 }
520             }
521         } else if (mController.getParams().allowOffline) {
522             ProvisionLogger.logi("Result is " + resultCode + ". Allowed offline provisioning.");
523             mController.performPlatformProvidedProvisioning();
524         } else if (isRoleHolderUpdaterRequestingPlatformDrivenProvisioning(resultData)) {
525             ProvisionLogger.logi("Result is " + resultCode + " and applied fallback strategy.");
526             mController.performPlatformProvidedProvisioning();
527         } else {
528             mAnalyticsTracker.logRoleHolderUpdaterUpdateFailed();
529             failRoleHolderUpdate();
530             ProvisionLogger.loge("Failed to perform a platform-requested role holder "
531                     + "update. Result is " + resultCode + " and allow offline provisioning"
532                     + " is " + mController.getParams().allowOffline);
533             SetupMetricsLogger.logMetrics(this, mScreenKey,
534                     SetupMetric.ofError(setupMetricScreenName, resultCode));
535         }
536     }
537 
538     private void handleRoleHolderRequestedUpdateResult(int resultCode, Intent resultData) {
539         if ((resultCode
540                 == RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_RECOVERABLE_ERROR
541                 || resultCode == RESULT_CANCELED)
542                 && mController.canRetryRoleHolderUpdate()) {
543             mController.startRoleHolderUpdaterWithLastState(
544                     /* isRoleHolderRequestedUpdate= */ true);
545             mController.incrementRoleHolderUpdateRetryCount();
546         } else if (resultCode
547                 == RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_PROVISIONING_DISABLED) {
548             mController.performPlatformProvidedProvisioning();
549         } else if (resultCode
550                 != RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_UNRECOVERABLE_ERROR) {
551             boolean isProvisioningStarted = mController.startAppropriateProvisioning(
552                     getIntent(),
553                     createRoleHolderAdditionalExtras(resultCode),
554                     getCallingPackage());
555             if (!isProvisioningStarted) {
556                 if (isRoleHolderUpdaterRequestingPlatformDrivenProvisioning(resultData)) {
557                     ProvisionLogger.logi("Result is " + resultCode
558                             + " and applied fallback strategy.");
559                     mController.performPlatformProvidedProvisioning();
560                 } else {
561                     failRoleHolderUpdate();
562                     ProvisionLogger.loge("Failed to start provisioning after a "
563                             + "role holder-requested role holder update. Result is "
564                             + resultCode + " and allow offline provisioning is "
565                             + mController.getParams().allowOffline);
566                     SetupMetricsLogger.logMetrics(this, mScreenKey,
567                             SetupMetric.ofError(setupMetricScreenName, resultCode));
568                 }
569             }
570         } else if (mController.getParams().allowOffline) {
571             ProvisionLogger.logi("Result is " + resultCode + ". Allowed offline provisioning.");
572             mController.performPlatformProvidedProvisioning();
573         } else if (isRoleHolderUpdaterRequestingPlatformDrivenProvisioning(resultData)) {
574             ProvisionLogger.logi("Result is " + resultCode + " and applied fallback strategy.");
575             mController.performPlatformProvidedProvisioning();
576         } else {
577             failRoleHolderUpdate();
578             ProvisionLogger.loge("Failed to perform a role holder-requested role holder "
579                     + "update. Result is " + resultCode + " and allow offline provisioning"
580                     + " is " + mController.getParams().allowOffline);
581             SetupMetricsLogger.logMetrics(this, mScreenKey,
582                     SetupMetric.ofError(setupMetricScreenName, resultCode));
583         }
584     }
585 
586     private boolean isRoleHolderUpdaterRequestingPlatformDrivenProvisioning(
587             @Nullable Intent resultData) {
588         if (resultData == null) {
589             return false;
590         }
591         return resultData.getIntExtra(
592                 EXTRA_ROLE_HOLDER_UPDATE_FAILURE_STRATEGY,
593                 ROLE_HOLDER_UPDATE_FAILURE_STRATEGY_FAIL_PROVISIONING)
594                 == ROLE_HOLDER_UPDATE_FAILURE_STRATEGY_FALLBACK_TO_PLATFORM_PROVISIONING;
595     }
596 
597     private void maybeHandleLaunchIntent(int resultCode, Intent data) {
598         if (data == null || !data.hasExtra(EXTRA_RESULT_LAUNCH_INTENT)) {
599             setResult(resultCode);
600             return;
601         }
602 
603         Intent launchIntent = data.getParcelableExtra(EXTRA_RESULT_LAUNCH_INTENT, Intent.class);
604         ProvisionLogger.logi("Role holder returned result intent: " + launchIntent);
605 
606         if (!mController.getParams().provisioningShouldLaunchResultIntent) {
607             ProvisionLogger.logi("Role Holder result intent to be launched by "
608                     + "provisioning initiator");
609             setResult(resultCode, launchIntent);
610             return;
611         }
612 
613         ProvisionLogger.logi("Role Holder result intent launched by platform");
614         startActivity(launchIntent);
615     }
616 
617     private void failRoleHolderUpdate() {
618         ProvisionLogger.loge("Update failed and offline provisioning is not allowed.");
619         SetupMetricsLogger.logMetrics(this, mScreenKey,
620                 SetupMetric.ofError(setupMetricScreenName, SETUP_METRIC_DEFAULT_ERROR_CODE));
621         if (mUtils.isOrganizationOwnedAllowed(mController.getParams())) {
622             showFactoryResetDialog(R.string.cant_set_up_device,
623                     R.string.contact_your_admin_for_help);
624         } else {
625             showErrorAndClose(
626                     R.string.cant_set_up_device,
627                     R.string.contact_your_admin_for_help,
628                     "Failed to provision personally-owned device.");
629         }
630     }
631 
632     private void showRoleHolderDownloadFailedDialog(@NonNull Intent data) {
633         int dialogTitleResId = data.getIntExtra(
634                 EXTRA_DIALOG_TITLE_ID,
635                 R.string.cant_set_up_device);
636         int dialogMessageResId = data.getIntExtra(
637                 EXTRA_ERROR_MESSAGE_RES_ID,
638                 R.string.contact_your_admin_for_help);
639         if (data.getBooleanExtra(EXTRA_FACTORY_RESET_REQUIRED, /* defaultValue= */ false)) {
640             showFactoryResetDialog(
641                     dialogTitleResId,
642                     dialogMessageResId);
643         } else {
644             showErrorAndClose(
645                     dialogTitleResId,
646                     dialogMessageResId,
647                     "Failed to provision personally-owned device.");
648         }
649     }
650 
651     private boolean isDpcInstalled() {
652         String adminPackageName = mController.getParams().inferDeviceAdminPackageName();
653         return mUtils.isPackageInstalled(adminPackageName, getPackageManager());
654     }
655 
656     private void handleAdminIntegratedFlowPreparerResult() {
657         if (isDpcInstalled()) {
658             startAdminIntegratedFlowPostDpcInstall();
659         } else {
660             String adminPackageName = mController.getParams().inferDeviceAdminPackageName();
661             showErrorAndClose(
662                     R.string.cant_set_up_device,
663                     R.string.contact_your_admin_for_help,
664                     "Package name " + adminPackageName + " is not installed.");
665         }
666     }
667 
668     @Override
669     public void showErrorAndClose(Integer titleId, int messageId, String logMessage) {
670         showErrorAndClose(LazyStringResource.of(titleId), LazyStringResource.of(messageId),
671                 logMessage);
672     }
673 
674     @Override
675     public void showErrorAndClose(
676             LazyStringResource title, LazyStringResource message, String logMessage) {
677         SimpleDialog.Builder dialogBuilder =
678                 new SimpleDialog.Builder().setTitle(title).setMessage(message);
679         setShowErrorAndCloseParams(dialogBuilder, logMessage);
680     }
681 
682     private void setShowErrorAndCloseParams(SimpleDialog.Builder dialogBuilder, String logText) {
683         ProvisionLogger.loge(logText);
684 
685         SimpleDialog.Builder builder =
686                 dialogBuilder
687                         .setCancelable(false)
688                         .setPositiveButtonMessage(R.string.device_owner_error_ok);
689         showDialog(builder, ERROR_AND_CLOSE_DIALOG);
690     }
691 
692     @Override
693     public void onNegativeButtonClick(DialogFragment dialog) {
694         switch (dialog.getTag()) {
695             case BACK_PRESSED_DIALOG_CLOSE_ACTIVITY:
696             case BACK_PRESSED_DIALOG_RESET:
697                 // user chose to continue. Do nothing
698                 break;
699             case LAUNCHER_INVALID_DIALOG:
700                 dialog.dismiss();
701                 break;
702             default:
703                 SimpleDialog.throwButtonClickHandlerNotImplemented(dialog);
704         }
705     }
706 
707     @Override
708     public void onPositiveButtonClick(DialogFragment dialog) {
709         switch (dialog.getTag()) {
710             case ERROR_AND_CLOSE_DIALOG:
711             case BACK_PRESSED_DIALOG_CLOSE_ACTIVITY:
712                 onProvisioningAborted();
713                 break;
714             case BACK_PRESSED_DIALOG_RESET:
715                 mUtils.factoryReset(this, "Provisioning cancelled by user on consent screen");
716                 onProvisioningAborted();
717                 break;
718             case LAUNCHER_INVALID_DIALOG:
719                 requestLauncherPick();
720                 break;
721             case ERROR_DIALOG_RESET:
722                 getUtils().factoryReset(this, "Error during preprovisioning");
723                 setResult(Activity.RESULT_CANCELED);
724                 getTransitionHelper().finishActivity(this);
725                 break;
726             default:
727                 SimpleDialog.throwButtonClickHandlerNotImplemented(dialog);
728         }
729     }
730 
731     private void onProvisioningAborted() {
732         setResult(Activity.RESULT_CANCELED);
733         mController.logPreProvisioningCancelled();
734         getTransitionHelper().finishActivity(this);
735     }
736 
737     @Override
738     public void requestEncryption(ProvisioningParams params) {
739         Intent encryptIntent = new Intent(this,
740                 getActivityForScreen(ManagedProvisioningScreens.ENCRYPT));
741         WizardManagerHelper.copyWizardManagerExtras(getIntent(), encryptIntent);
742         encryptIntent.putExtra(ProvisioningParams.EXTRA_PROVISIONING_PARAMS, params);
743         getTransitionHelper().startActivityForResultWithTransition(
744                 this, encryptIntent, ENCRYPT_DEVICE_REQUEST_CODE);
745     }
746 
747     @Override
748     public void requestWifiPick() {
749         final Intent intent = mUtils.getWifiPickIntent();
750         WizardManagerHelper.copyWizardManagerExtras(getIntent(), intent);
751         getTransitionHelper()
752                 .startActivityForResultWithTransition(this, intent, WIFI_REQUEST_CODE);
753     }
754 
755     @Override
756     public void showCurrentLauncherInvalid() {
757         SimpleDialog.Builder dialogBuilder = new SimpleDialog.Builder()
758                 .setCancelable(false)
759                 .setTitle(R.string.change_device_launcher)
760                 .setMessage(R.string.launcher_app_cant_be_used_by_work_profile)
761                 .setNegativeButtonMessage(R.string.cancel_provisioning)
762                 .setPositiveButtonMessage(R.string.pick_launcher);
763         showDialog(dialogBuilder, LAUNCHER_INVALID_DIALOG);
764     }
765 
766     @Override
767     public void abortProvisioning() {
768         onProvisioningAborted();
769     }
770 
771     @Override
772     public void prepareAdminIntegratedFlow(ProvisioningParams params) {
773         if (AdminIntegratedFlowPrepareActivity.shouldRunPrepareActivity(mUtils, this, params)) {
774             Intent intent = new Intent(this,
775                     getActivityForScreen(ManagedProvisioningScreens.ADMIN_INTEGRATED_PREPARE));
776             WizardManagerHelper.copyWizardManagerExtras(getIntent(), intent);
777             intent.putExtra(ProvisioningParams.EXTRA_PROVISIONING_PARAMS, params);
778             getTransitionHelper().startActivityForResultWithTransition(
779                     this, intent, ADMIN_INTEGRATED_FLOW_PREPARE_REQUEST_CODE);
780         } else {
781             handleAdminIntegratedFlowPreparerResult();
782         }
783     }
784 
785     @Override
786     public void startRoleHolderUpdater(boolean isRoleHolderRequestedUpdate) {
787         DeviceManagementRoleHolderUpdaterHelper roleHolderUpdaterHelper =
788                 new DeviceManagementRoleHolderUpdaterHelper(
789                         mRoleHolderUpdaterProvider.getPackageName(this),
790                         RoleHolderProvider.DEFAULT.getPackageName(this),
791                         new DefaultPackageInstallChecker(getPackageManager(), mUtils),
792                         new DefaultIntentResolverChecker(getPackageManager()),
793                         new DefaultFeatureFlagChecker(getContentResolver()));
794         Intent intent = new Intent(this, getActivityForScreen(RETRY_LAUNCH));
795         intent.putExtra(
796                 EXTRA_INTENT_TO_LAUNCH,
797                 roleHolderUpdaterHelper.createRoleHolderUpdaterIntent(
798                         getIntent(),
799                         getIntent().getIntExtra(
800                                 EXTRA_PROVISIONING_TRIGGER, PROVISIONING_TRIGGER_UNSPECIFIED),
801                         isRoleHolderRequestedUpdate));
802         mAnalyticsTracker.logRoleHolderUpdaterUpdateStart();
803         getTransitionHelper().startActivityForResultWithTransition(
804                  this,
805                 intent,
806                 isRoleHolderRequestedUpdate
807                         ? START_ROLE_HOLDER_REQUESTED_UPDATE_REQUEST_CODE
808                         : START_PLATFORM_REQUESTED_ROLE_HOLDER_UPDATE_REQUEST_CODE);
809     }
810 
811     @Override
812     public void startRoleHolderProvisioning(Intent intent) {
813         mAnalyticsTracker.logRoleHolderProvisioningStart();
814         Intent retryLaunchIntent = new Intent(this, getActivityForScreen(RETRY_LAUNCH));
815         retryLaunchIntent.putExtra(RetryLaunchActivity.EXTRA_INTENT_TO_LAUNCH, intent);
816         getTransitionHelper().startActivityForResultWithTransition(
817                 /* activity= */ this,
818                 retryLaunchIntent,
819                 START_DEVICE_MANAGEMENT_ROLE_HOLDER_PROVISIONING_REQUEST_CODE);
820     }
821 
822     @Override
823     public void onParamsValidated(ProvisioningParams params) {
824         ManagedProvisioningBaseApplication application =
825                 (ManagedProvisioningBaseApplication) getApplication();
826         application.keepScreenOn(this);
827     }
828 
829     @Override
830     public void startPlatformDrivenRoleHolderDownload() {
831         mAnalyticsTracker.logPlatformRoleHolderUpdateStart();
832         Intent intent = new Intent(this,
833                 getActivityForScreen(ManagedProvisioningScreens.DOWNLOAD_ROLE_HOLDER));
834         WizardManagerHelper.copyWizardManagerExtras(getIntent(), intent);
835         intent.putExtra(ProvisioningParams.EXTRA_PROVISIONING_PARAMS,
836                 mController.getParams());
837         getTransitionHelper().startActivityForResultWithTransition(
838                 this, intent, DOWNLOAD_DEVICE_MANAGEMENT_ROLE_HOLDER_FROM_PLATFORM_REQUEST_CODE);
839     }
840 
841     private void requestLauncherPick() {
842         Intent changeLauncherIntent = new Intent(Settings.ACTION_HOME_SETTINGS);
843         changeLauncherIntent.putExtra(EXTRA_SUPPORT_MANAGED_PROFILES, true);
844         getTransitionHelper().startActivityForResultWithTransition(
845                 this, changeLauncherIntent, CHANGE_LAUNCHER_REQUEST_CODE);
846     }
847 
848     /**
849      * Starts {@link ProvisioningActivity}.
850      */
851     @Override
852     public void startProvisioning(ProvisioningParams params) {
853         Intent intent = new Intent(this,
854                 getActivityForScreen(ManagedProvisioningScreens.PROVISIONING));
855         WizardManagerHelper.copyWizardManagerExtras(getIntent(), intent);
856         intent.putExtra(ProvisioningParams.EXTRA_PROVISIONING_PARAMS, params);
857         getTransitionHelper().startActivityForResultWithTransition(
858                 this, intent, PROVISIONING_REQUEST_CODE);
859     }
860 
861     // TODO: The below group of methods do not belong in the activity.
862     // Move them to the controller instead.
863     /**
864      * Starts either the admin-integrated or the legacy flow, depending on the device state and
865      * DPC capabilities.
866      */
867     private void startAdminIntegratedFlowPostDpcInstall() {
868         boolean canPerformAdminIntegratedFlow = mUtils.canPerformAdminIntegratedFlow(
869                 this,
870                 mController.getParams(),
871                 mController.getPolicyComplianceUtils(),
872                 mController.getGetProvisioningModeUtils());
873         if (canPerformAdminIntegratedFlow) {
874             startAdminIntegratedFlowWithoutPredeterminedMode();
875         } else {
876             ProvisionLogger.loge("The admin app does not have handlers for both "
877                     + "ACTION_GET_PROVISIONING_MODE and ACTION_ADMIN_POLICY_COMPLIANCE "
878                     + "intent actions.");
879             SetupMetricsLogger.logMetrics(this, mScreenKey,
880                     SetupMetric.ofError(setupMetricScreenName, SETUP_METRIC_DEFAULT_ERROR_CODE));
881             if (mUtils.isOrganizationOwnedAllowed(mController.getParams())) {
882                 showFactoryResetDialog(R.string.cant_set_up_device,
883                         R.string.contact_your_admin_for_help);
884             } else {
885                 showErrorAndClose(
886                         R.string.cant_set_up_device,
887                         R.string.contact_your_admin_for_help,
888                         "Failed provisioning personally-owned device.");
889             }
890         }
891         mController.logProvisioningFlowType();
892     }
893 
894     private void startAdminIntegratedFlowWithoutPredeterminedMode() {
895         ProvisionLogger.logi("Starting the admin-integrated flow.");
896         GetProvisioningModeUtils provisioningModeUtils = mController.getGetProvisioningModeUtils();
897         Bundle additionalExtras = mController.getAdditionalExtrasForGetProvisioningModeIntent();
898         provisioningModeUtils.startGetProvisioningModeActivityIfResolved(
899                 this, mController.getParams(), additionalExtras,
900                 GET_PROVISIONING_MODE_REQUEST_CODE, getTransitionHelper());
901     }
902 
903     private void startFinancedDeviceFlow() {
904         ProvisionLogger.logi("Starting the financed device flow.");
905         mController.updateProvisioningFlowState(FLOW_TYPE_LEGACY);
906         mController.continueProvisioningAfterUserConsent();
907     }
908 
909     @Override
910     public void showFactoryResetDialog(Integer titleId, int messageId) {
911         SimpleDialog.Builder dialogBuilder = new SimpleDialog.Builder()
912                 .setTitle(titleId)
913                 .setMessage(messageId)
914                 .setCancelable(false)
915                 .setPositiveButtonMessage(R.string.reset);
916 
917         showDialog(dialogBuilder, ERROR_DIALOG_RESET);
918     }
919 
920     @Override
921     public void initiateUi(UiParams uiParams) {
922         mBridge.initiateUi(uiParams);
923     }
924 
925     @Override
926     public void showOwnershipDisclaimerScreen(ProvisioningParams params) {
927         Intent intent = new Intent(this,
928                 getActivityForScreen(ManagedProvisioningScreens.LANDING));
929         WizardManagerHelper.copyWizardManagerExtras(getIntent(), intent);
930         intent.putExtra(ProvisioningParams.EXTRA_PROVISIONING_PARAMS, params);
931         getTransitionHelper().startActivityForResultWithTransition(
932                 this, intent, ORGANIZATION_OWNED_LANDING_PAGE_REQUEST_CODE);
933     }
934 
935     @Override
936     public void prepareFinancedDeviceFlow(ProvisioningParams params) {
937         Intent intent = new Intent(this,
938                 getActivityForScreen(ManagedProvisioningScreens.FINANCED_DEVICE_LANDING));
939         WizardManagerHelper.copyWizardManagerExtras(getIntent(), intent);
940         intent.putExtra(ProvisioningParams.EXTRA_PROVISIONING_PARAMS, params);
941         getTransitionHelper().startActivityForResultWithTransition(
942                 this, intent, FINANCED_DEVICE_PREPARE_REQUEST_CODE);
943     }
944 
945     @Override
946     public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
947         super.onCreateContextMenu(menu, v, menuInfo);
948         if (v instanceof TextView) {
949             mContextMenuMaker.populateMenuContent(menu, (TextView) v);
950         }
951     }
952 
953     @Override
954     public void onBackPressed() {
955         if (mUtils.isOrganizationOwnedAllowed(mController.getParams())) {
956             showDialog(mUtils.createCancelProvisioningResetDialogBuilder(getApplicationContext()),
957                     BACK_PRESSED_DIALOG_RESET);
958         } else {
959             showDialog(mUtils.createCancelProvisioningDialogBuilder(),
960                     BACK_PRESSED_DIALOG_CLOSE_ACTIVITY);
961         }
962     }
963 
964     private void logMetrics() {
965         int nightMode = getResources().getConfiguration().uiMode & UI_MODE_NIGHT_MASK;
966         mAnalyticsTracker.logIsNightMode(nightMode == UI_MODE_NIGHT_YES);
967     }
968 
969     /**
970      * Constructs {@link PreProvisioningActivityController} for a given {@link
971      * PreProvisioningActivity}
972      */
973     interface ControllerProvider {
974         /**
975          * Constructs {@link PreProvisioningActivityController} for a given {@link
976          * PreProvisioningActivity}
977          */
978         PreProvisioningActivityController getInstance(PreProvisioningActivity activity);
979     }
980 }
981