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