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