1 /* 2 * Copyright 2019, 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.finalization; 18 19 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE; 20 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE; 21 22 import static com.android.internal.util.Preconditions.checkNotNull; 23 24 import android.annotation.IntDef; 25 import android.app.Activity; 26 import android.app.NotificationManager; 27 import android.os.Bundle; 28 29 import com.android.internal.annotations.VisibleForTesting; 30 import com.android.managedprovisioning.analytics.DeferredMetricsReader; 31 import com.android.managedprovisioning.common.NotificationHelper; 32 import com.android.managedprovisioning.common.ProvisionLogger; 33 import com.android.managedprovisioning.common.SettingsFacade; 34 import com.android.managedprovisioning.common.Utils; 35 import com.android.managedprovisioning.model.ProvisioningParams; 36 import com.android.managedprovisioning.provisioning.Constants; 37 38 import java.io.File; 39 40 /** 41 * Controller for the finalization of managed provisioning. This class should be invoked after 42 * {@link PreFinalizationController}. Provisioning is finalized via calls to 43 * {@link #provisioningFinalized()} and {@link #commitFinalizedState()}. Different instances of 44 * this class will be tailored to run these two methods at different points in the Setup Wizard user 45 * flows, based on the type of FinalizationControllerLogic they are constructed with. 46 */ 47 public final class FinalizationController { 48 49 static final int PROVISIONING_FINALIZED_RESULT_NO_CHILD_ACTIVITY_LAUNCHED = 1; 50 static final int PROVISIONING_FINALIZED_RESULT_CHILD_ACTIVITY_LAUNCHED = 2; 51 static final int PROVISIONING_FINALIZED_RESULT_SKIPPED = 3; 52 @IntDef({ 53 PROVISIONING_FINALIZED_RESULT_NO_CHILD_ACTIVITY_LAUNCHED, 54 PROVISIONING_FINALIZED_RESULT_CHILD_ACTIVITY_LAUNCHED, 55 PROVISIONING_FINALIZED_RESULT_SKIPPED}) 56 @interface ProvisioningFinalizedResult {} 57 58 private static final int DPC_SETUP_REQUEST_CODE = 1; 59 private static final int FINAL_SCREEN_REQUEST_CODE = 2; 60 61 private final FinalizationControllerLogic mFinalizationControllerLogic; 62 private final Activity mActivity; 63 private final Utils mUtils; 64 private final SettingsFacade mSettingsFacade; 65 private final UserProvisioningStateHelper mUserProvisioningStateHelper; 66 private final ProvisioningIntentProvider mProvisioningIntentProvider; 67 private final NotificationHelper mNotificationHelper; 68 private final DeferredMetricsReader mDeferredMetricsReader; 69 private @ProvisioningFinalizedResult int mProvisioningFinalizedResult; 70 private ProvisioningParamsUtils mProvisioningParamsUtils; 71 FinalizationController(Activity activity, FinalizationControllerLogic finalizationControllerLogic, UserProvisioningStateHelper userProvisioningStateHelper)72 public FinalizationController(Activity activity, 73 FinalizationControllerLogic finalizationControllerLogic, 74 UserProvisioningStateHelper userProvisioningStateHelper) { 75 this( 76 activity, 77 finalizationControllerLogic, 78 new Utils(), 79 new SettingsFacade(), 80 userProvisioningStateHelper, 81 new NotificationHelper(activity), 82 new DeferredMetricsReader( 83 Constants.getDeferredMetricsFile(activity)), 84 new ProvisioningParamsUtils()); 85 } 86 FinalizationController(Activity activity, FinalizationControllerLogic finalizationControllerLogic)87 public FinalizationController(Activity activity, 88 FinalizationControllerLogic finalizationControllerLogic) { 89 this( 90 activity, 91 finalizationControllerLogic, 92 new Utils(), 93 new SettingsFacade(), 94 new UserProvisioningStateHelper(activity), 95 new NotificationHelper(activity), 96 new DeferredMetricsReader( 97 Constants.getDeferredMetricsFile(activity)), 98 new ProvisioningParamsUtils()); 99 } 100 101 @VisibleForTesting FinalizationController(Activity activity, FinalizationControllerLogic finalizationControllerLogic, Utils utils, SettingsFacade settingsFacade, UserProvisioningStateHelper helper, NotificationHelper notificationHelper, DeferredMetricsReader deferredMetricsReader, ProvisioningParamsUtils provisioningParamsUtils)102 FinalizationController(Activity activity, 103 FinalizationControllerLogic finalizationControllerLogic, 104 Utils utils, 105 SettingsFacade settingsFacade, 106 UserProvisioningStateHelper helper, 107 NotificationHelper notificationHelper, 108 DeferredMetricsReader deferredMetricsReader, 109 ProvisioningParamsUtils provisioningParamsUtils) { 110 mActivity = checkNotNull(activity); 111 mFinalizationControllerLogic = checkNotNull(finalizationControllerLogic); 112 mUtils = checkNotNull(utils); 113 mSettingsFacade = checkNotNull(settingsFacade); 114 mUserProvisioningStateHelper = checkNotNull(helper); 115 mProvisioningIntentProvider = new ProvisioningIntentProvider(); 116 mNotificationHelper = checkNotNull(notificationHelper); 117 mDeferredMetricsReader = checkNotNull(deferredMetricsReader); 118 mProvisioningParamsUtils = provisioningParamsUtils; 119 } 120 121 @VisibleForTesting getPrimaryProfileFinalizationHelper( ProvisioningParams params)122 final PrimaryProfileFinalizationHelper getPrimaryProfileFinalizationHelper( 123 ProvisioningParams params) { 124 return new PrimaryProfileFinalizationHelper(params.accountToMigrate, 125 params.keepAccountMigrated, mUtils.getManagedProfile(mActivity), 126 params.inferDeviceAdminPackageName(), mUtils, 127 mUtils.isAdminIntegratedFlow(params)); 128 } 129 130 /** 131 * This method is invoked when provisioning is finalized. 132 * 133 * <p>This method has to be invoked after 134 * {@link PreFinalizationController#deviceManagementEstablished(ProvisioningParams)} 135 * was called. It is commonly invoked at the end of the setup flow, if provisioning occurs 136 * during the setup flow. It loads the provisioning params from the storage, notifies the DPC 137 * about the completed provisioning and sets the right user provisioning states. 138 * 139 * <p>To retrieve the resulting state of this method, use 140 * {@link #getProvisioningFinalizedResult()} 141 * 142 * <p>This method may be called multiple times. {@link #commitFinalizedState()} ()} must be 143 * called after the final call to this method. If this method is called again after that, it 144 * will return immediately without taking any action. 145 */ provisioningFinalized()146 final void provisioningFinalized() { 147 mProvisioningFinalizedResult = PROVISIONING_FINALIZED_RESULT_SKIPPED; 148 149 if (mUserProvisioningStateHelper.isStateUnmanagedOrFinalized()) { 150 ProvisionLogger.logw("provisioningFinalized called, but state is finalized or " 151 + "unmanaged"); 152 return; 153 } 154 155 final ProvisioningParams params = loadProvisioningParams(); 156 if (params == null) { 157 ProvisionLogger.logw("FinalizationController invoked, but no stored params"); 158 return; 159 } 160 161 if (!mFinalizationControllerLogic.isReadyForFinalization(params)) { 162 return; 163 } 164 165 mProvisioningFinalizedResult = PROVISIONING_FINALIZED_RESULT_NO_CHILD_ACTIVITY_LAUNCHED; 166 if (mUtils.isAdminIntegratedFlow(params)) { 167 // Don't send ACTION_PROFILE_PROVISIONING_COMPLETE broadcast to DPC or launch DPC by 168 // ACTION_PROVISIONING_SUCCESSFUL intent if it's admin integrated flow. 169 if (mUtils.isDeviceOwnerAction(params.provisioningAction)) { 170 mProvisioningIntentProvider.launchFinalizationScreenForResult(mActivity, params, 171 FINAL_SCREEN_REQUEST_CODE); 172 mProvisioningFinalizedResult = 173 PROVISIONING_FINALIZED_RESULT_CHILD_ACTIVITY_LAUNCHED; 174 } 175 } else { 176 if (params.provisioningAction.equals(ACTION_PROVISION_MANAGED_PROFILE)) { 177 mProvisioningFinalizedResult = 178 mFinalizationControllerLogic.notifyDpcManagedProfile( 179 params, DPC_SETUP_REQUEST_CODE); 180 } else { 181 mProvisioningFinalizedResult = 182 mFinalizationControllerLogic.notifyDpcManagedDeviceOrUser( 183 params, DPC_SETUP_REQUEST_CODE); 184 } 185 } 186 } 187 188 /** 189 * @throws IllegalStateException if {@link #provisioningFinalized()} was not called before. 190 */ getProvisioningFinalizedResult()191 final @ProvisioningFinalizedResult int getProvisioningFinalizedResult() { 192 if (mProvisioningFinalizedResult == 0) { 193 throw new IllegalStateException("provisioningFinalized() has not been called."); 194 } 195 return mProvisioningFinalizedResult; 196 } 197 198 @VisibleForTesting clearParamsFile()199 final void clearParamsFile() { 200 final File file = mProvisioningParamsUtils.getProvisioningParamsFile(mActivity); 201 if (file != null) { 202 file.delete(); 203 } 204 } 205 loadProvisioningParams()206 private ProvisioningParams loadProvisioningParams() { 207 final File file = mProvisioningParamsUtils.getProvisioningParamsFile(mActivity); 208 final ProvisioningParams params = ProvisioningParams.load(file); 209 return params; 210 } 211 212 /** 213 * Update the system's provisioning state, and commit any other irreversible changes that 214 * must wait until finalization is 100% completed. 215 */ commitFinalizedState(ProvisioningParams params)216 private void commitFinalizedState(ProvisioningParams params) { 217 if (ACTION_PROVISION_MANAGED_DEVICE.equals(params.provisioningAction)) { 218 mNotificationHelper.showPrivacyReminderNotification( 219 mActivity, NotificationManager.IMPORTANCE_DEFAULT); 220 } else if (ACTION_PROVISION_MANAGED_PROFILE.equals(params.provisioningAction) 221 && mFinalizationControllerLogic.shouldFinalizePrimaryProfile(params)) { 222 getPrimaryProfileFinalizationHelper(params) 223 .finalizeProvisioningInPrimaryProfile(mActivity, null); 224 } 225 226 mUserProvisioningStateHelper.markUserProvisioningStateFinalized(params); 227 228 mDeferredMetricsReader.scheduleDumpMetrics(mActivity); 229 clearParamsFile(); 230 } 231 232 /** 233 * This method is called by the parent activity to force the final commit of all state changes. 234 * After this is called, any further calls to {@link #provisioningFinalized()} will return 235 * immediately without taking any action. 236 */ commitFinalizedState()237 final void commitFinalizedState() { 238 final ProvisioningParams params = loadProvisioningParams(); 239 if (params == null) { 240 ProvisionLogger.logw( 241 "Attempt to commitFinalizedState when params have already been deleted"); 242 } else { 243 commitFinalizedState(loadProvisioningParams()); 244 } 245 } 246 247 /** 248 * This method is called when onSaveInstanceState() executes on the finalization activity. 249 */ saveInstanceState(Bundle outState)250 final void saveInstanceState(Bundle outState) { 251 mFinalizationControllerLogic.saveInstanceState(outState); 252 } 253 254 /** 255 * When saved instance state is passed to the finalization activity in its onCreate() method, 256 * that state is passed to the FinalizationControllerLogic object here so it can be restored. 257 */ restoreInstanceState(Bundle savedInstanceState)258 final void restoreInstanceState(Bundle savedInstanceState) { 259 mFinalizationControllerLogic.restoreInstanceState(savedInstanceState, 260 loadProvisioningParams()); 261 } 262 263 /** 264 * Cleanup that must happen when the finalization activity is destroyed, even if we haven't yet 265 * called {@link #commitFinalizedState()} to finalize the system's provisioning state. 266 */ activityDestroyed(boolean isFinishing)267 final void activityDestroyed(boolean isFinishing) { 268 mFinalizationControllerLogic.activityDestroyed(isFinishing); 269 } 270 } 271