| /* |
| * Copyright 2019, The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.managedprovisioning.finalization; |
| |
| import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE; |
| import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE; |
| |
| import static com.android.internal.util.Preconditions.checkNotNull; |
| |
| import android.annotation.IntDef; |
| import android.app.Activity; |
| import android.app.NotificationManager; |
| import android.os.Bundle; |
| |
| import com.android.internal.annotations.VisibleForTesting; |
| import com.android.managedprovisioning.analytics.DeferredMetricsReader; |
| import com.android.managedprovisioning.common.NotificationHelper; |
| import com.android.managedprovisioning.common.ProvisionLogger; |
| import com.android.managedprovisioning.common.SettingsFacade; |
| import com.android.managedprovisioning.common.Utils; |
| import com.android.managedprovisioning.model.ProvisioningParams; |
| import com.android.managedprovisioning.provisioning.Constants; |
| |
| import java.io.File; |
| |
| /** |
| * Controller for the finalization of managed provisioning. This class should be invoked after |
| * {@link PreFinalizationController}. Provisioning is finalized via calls to |
| * {@link #provisioningFinalized()} and {@link #commitFinalizedState()}. Different instances of |
| * this class will be tailored to run these two methods at different points in the Setup Wizard user |
| * flows, based on the type of FinalizationControllerLogic they are constructed with. |
| */ |
| public final class FinalizationController { |
| |
| static final int PROVISIONING_FINALIZED_RESULT_NO_CHILD_ACTIVITY_LAUNCHED = 1; |
| static final int PROVISIONING_FINALIZED_RESULT_CHILD_ACTIVITY_LAUNCHED = 2; |
| static final int PROVISIONING_FINALIZED_RESULT_SKIPPED = 3; |
| @IntDef({ |
| PROVISIONING_FINALIZED_RESULT_NO_CHILD_ACTIVITY_LAUNCHED, |
| PROVISIONING_FINALIZED_RESULT_CHILD_ACTIVITY_LAUNCHED, |
| PROVISIONING_FINALIZED_RESULT_SKIPPED}) |
| @interface ProvisioningFinalizedResult {} |
| |
| private static final int DPC_SETUP_REQUEST_CODE = 1; |
| private static final int FINAL_SCREEN_REQUEST_CODE = 2; |
| |
| private final FinalizationControllerLogic mFinalizationControllerLogic; |
| private final Activity mActivity; |
| private final Utils mUtils; |
| private final SettingsFacade mSettingsFacade; |
| private final UserProvisioningStateHelper mUserProvisioningStateHelper; |
| private final ProvisioningIntentProvider mProvisioningIntentProvider; |
| private final NotificationHelper mNotificationHelper; |
| private final DeferredMetricsReader mDeferredMetricsReader; |
| private @ProvisioningFinalizedResult int mProvisioningFinalizedResult; |
| private ProvisioningParamsUtils mProvisioningParamsUtils; |
| |
| public FinalizationController(Activity activity, |
| FinalizationControllerLogic finalizationControllerLogic, |
| UserProvisioningStateHelper userProvisioningStateHelper) { |
| this( |
| activity, |
| finalizationControllerLogic, |
| new Utils(), |
| new SettingsFacade(), |
| userProvisioningStateHelper, |
| new NotificationHelper(activity), |
| new DeferredMetricsReader( |
| Constants.getDeferredMetricsFile(activity)), |
| new ProvisioningParamsUtils()); |
| } |
| |
| public FinalizationController(Activity activity, |
| FinalizationControllerLogic finalizationControllerLogic) { |
| this( |
| activity, |
| finalizationControllerLogic, |
| new Utils(), |
| new SettingsFacade(), |
| new UserProvisioningStateHelper(activity), |
| new NotificationHelper(activity), |
| new DeferredMetricsReader( |
| Constants.getDeferredMetricsFile(activity)), |
| new ProvisioningParamsUtils()); |
| } |
| |
| @VisibleForTesting |
| FinalizationController(Activity activity, |
| FinalizationControllerLogic finalizationControllerLogic, |
| Utils utils, |
| SettingsFacade settingsFacade, |
| UserProvisioningStateHelper helper, |
| NotificationHelper notificationHelper, |
| DeferredMetricsReader deferredMetricsReader, |
| ProvisioningParamsUtils provisioningParamsUtils) { |
| mActivity = checkNotNull(activity); |
| mFinalizationControllerLogic = checkNotNull(finalizationControllerLogic); |
| mUtils = checkNotNull(utils); |
| mSettingsFacade = checkNotNull(settingsFacade); |
| mUserProvisioningStateHelper = checkNotNull(helper); |
| mProvisioningIntentProvider = new ProvisioningIntentProvider(); |
| mNotificationHelper = checkNotNull(notificationHelper); |
| mDeferredMetricsReader = checkNotNull(deferredMetricsReader); |
| mProvisioningParamsUtils = provisioningParamsUtils; |
| } |
| |
| @VisibleForTesting |
| final PrimaryProfileFinalizationHelper getPrimaryProfileFinalizationHelper( |
| ProvisioningParams params) { |
| return new PrimaryProfileFinalizationHelper(params.accountToMigrate, |
| params.keepAccountMigrated, mUtils.getManagedProfile(mActivity), |
| params.inferDeviceAdminPackageName(), mUtils, |
| mUtils.isAdminIntegratedFlow(params)); |
| } |
| |
| /** |
| * This method is invoked when provisioning is finalized. |
| * |
| * <p>This method has to be invoked after |
| * {@link PreFinalizationController#deviceManagementEstablished(ProvisioningParams)} |
| * was called. It is commonly invoked at the end of the setup flow, if provisioning occurs |
| * during the setup flow. It loads the provisioning params from the storage, notifies the DPC |
| * about the completed provisioning and sets the right user provisioning states. |
| * |
| * <p>To retrieve the resulting state of this method, use |
| * {@link #getProvisioningFinalizedResult()} |
| * |
| * <p>This method may be called multiple times. {@link #commitFinalizedState()} ()} must be |
| * called after the final call to this method. If this method is called again after that, it |
| * will return immediately without taking any action. |
| */ |
| final void provisioningFinalized() { |
| mProvisioningFinalizedResult = PROVISIONING_FINALIZED_RESULT_SKIPPED; |
| |
| if (mUserProvisioningStateHelper.isStateUnmanagedOrFinalized()) { |
| ProvisionLogger.logw("provisioningFinalized called, but state is finalized or " |
| + "unmanaged"); |
| return; |
| } |
| |
| final ProvisioningParams params = loadProvisioningParams(); |
| if (params == null) { |
| ProvisionLogger.logw("FinalizationController invoked, but no stored params"); |
| return; |
| } |
| |
| if (!mFinalizationControllerLogic.isReadyForFinalization(params)) { |
| return; |
| } |
| |
| mProvisioningFinalizedResult = PROVISIONING_FINALIZED_RESULT_NO_CHILD_ACTIVITY_LAUNCHED; |
| if (mUtils.isAdminIntegratedFlow(params)) { |
| // Don't send ACTION_PROFILE_PROVISIONING_COMPLETE broadcast to DPC or launch DPC by |
| // ACTION_PROVISIONING_SUCCESSFUL intent if it's admin integrated flow. |
| if (mUtils.isDeviceOwnerAction(params.provisioningAction)) { |
| mProvisioningIntentProvider.launchFinalizationScreenForResult(mActivity, params, |
| FINAL_SCREEN_REQUEST_CODE); |
| mProvisioningFinalizedResult = |
| PROVISIONING_FINALIZED_RESULT_CHILD_ACTIVITY_LAUNCHED; |
| } |
| } else { |
| if (params.provisioningAction.equals(ACTION_PROVISION_MANAGED_PROFILE)) { |
| mProvisioningFinalizedResult = |
| mFinalizationControllerLogic.notifyDpcManagedProfile( |
| params, DPC_SETUP_REQUEST_CODE); |
| } else { |
| mProvisioningFinalizedResult = |
| mFinalizationControllerLogic.notifyDpcManagedDeviceOrUser( |
| params, DPC_SETUP_REQUEST_CODE); |
| } |
| } |
| } |
| |
| /** |
| * @throws IllegalStateException if {@link #provisioningFinalized()} was not called before. |
| */ |
| final @ProvisioningFinalizedResult int getProvisioningFinalizedResult() { |
| if (mProvisioningFinalizedResult == 0) { |
| throw new IllegalStateException("provisioningFinalized() has not been called."); |
| } |
| return mProvisioningFinalizedResult; |
| } |
| |
| @VisibleForTesting |
| final void clearParamsFile() { |
| final File file = mProvisioningParamsUtils.getProvisioningParamsFile(mActivity); |
| if (file != null) { |
| file.delete(); |
| } |
| } |
| |
| private ProvisioningParams loadProvisioningParams() { |
| final File file = mProvisioningParamsUtils.getProvisioningParamsFile(mActivity); |
| final ProvisioningParams params = ProvisioningParams.load(file); |
| return params; |
| } |
| |
| /** |
| * Update the system's provisioning state, and commit any other irreversible changes that |
| * must wait until finalization is 100% completed. |
| */ |
| private void commitFinalizedState(ProvisioningParams params) { |
| if (ACTION_PROVISION_MANAGED_DEVICE.equals(params.provisioningAction)) { |
| mNotificationHelper.showPrivacyReminderNotification( |
| mActivity, NotificationManager.IMPORTANCE_DEFAULT); |
| } else if (ACTION_PROVISION_MANAGED_PROFILE.equals(params.provisioningAction) |
| && mFinalizationControllerLogic.shouldFinalizePrimaryProfile(params)) { |
| getPrimaryProfileFinalizationHelper(params) |
| .finalizeProvisioningInPrimaryProfile(mActivity, null); |
| } |
| |
| mUserProvisioningStateHelper.markUserProvisioningStateFinalized(params); |
| |
| mDeferredMetricsReader.scheduleDumpMetrics(mActivity); |
| clearParamsFile(); |
| } |
| |
| /** |
| * This method is called by the parent activity to force the final commit of all state changes. |
| * After this is called, any further calls to {@link #provisioningFinalized()} will return |
| * immediately without taking any action. |
| */ |
| final void commitFinalizedState() { |
| final ProvisioningParams params = loadProvisioningParams(); |
| if (params == null) { |
| ProvisionLogger.logw( |
| "Attempt to commitFinalizedState when params have already been deleted"); |
| } else { |
| commitFinalizedState(loadProvisioningParams()); |
| } |
| } |
| |
| /** |
| * This method is called when onSaveInstanceState() executes on the finalization activity. |
| */ |
| final void saveInstanceState(Bundle outState) { |
| mFinalizationControllerLogic.saveInstanceState(outState); |
| } |
| |
| /** |
| * When saved instance state is passed to the finalization activity in its onCreate() method, |
| * that state is passed to the FinalizationControllerLogic object here so it can be restored. |
| */ |
| final void restoreInstanceState(Bundle savedInstanceState) { |
| mFinalizationControllerLogic.restoreInstanceState(savedInstanceState, |
| loadProvisioningParams()); |
| } |
| |
| /** |
| * Cleanup that must happen when the finalization activity is destroyed, even if we haven't yet |
| * called {@link #commitFinalizedState()} to finalize the system's provisioning state. |
| */ |
| final void activityDestroyed(boolean isFinishing) { |
| mFinalizationControllerLogic.activityDestroyed(isFinishing); |
| } |
| } |