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.provisioning; 18 19 import android.annotation.IntDef; 20 import android.app.Activity; 21 import android.app.DialogFragment; 22 import android.os.Bundle; 23 24 import androidx.annotation.VisibleForTesting; 25 26 import com.android.managedprovisioning.R; 27 import com.android.managedprovisioning.common.DialogBuilder; 28 import com.android.managedprovisioning.common.SettingsFacade; 29 import com.android.managedprovisioning.common.SetupGlifLayoutActivity; 30 import com.android.managedprovisioning.common.SimpleDialog; 31 import com.android.managedprovisioning.common.ThemeHelper; 32 import com.android.managedprovisioning.common.Utils; 33 import com.android.managedprovisioning.model.ProvisioningParams; 34 35 import java.lang.annotation.Retention; 36 import java.lang.annotation.RetentionPolicy; 37 38 /** 39 * Abstract class for provisioning activity. 40 * 41 * <p>This activity registers for updates of the provisioning process from the 42 * {@link ProvisioningManager}. It shows progress updates as provisioning progresses and handles 43 * showing of cancel and error dialogs.</p> 44 */ 45 // TODO(b/123288153): Rearrange provisioning activity, manager, controller classes. 46 public abstract class AbstractProvisioningActivity extends SetupGlifLayoutActivity 47 implements SimpleDialog.SimpleDialogListener, ProvisioningManagerCallback { 48 49 private static final String KEY_ACTIVITY_STATE = "activity-state"; 50 51 static final int STATE_PROVISIONING_INTIIALIZING = 1; 52 static final int STATE_PROVISIONING_STARTED = 2; 53 static final int STATE_PROVISIONING_COMPLETED = 3; 54 static final int STATE_PROVISIONING_FINALIZED = 4; 55 56 @Retention(RetentionPolicy.SOURCE) 57 @IntDef({STATE_PROVISIONING_INTIIALIZING, 58 STATE_PROVISIONING_STARTED, 59 STATE_PROVISIONING_COMPLETED, 60 STATE_PROVISIONING_FINALIZED}) 61 private @interface ProvisioningState {} 62 63 @VisibleForTesting static final String ERROR_DIALOG_OK = "ErrorDialogOk"; 64 @VisibleForTesting static final String ERROR_DIALOG_RESET = "ErrorDialogReset"; 65 @VisibleForTesting static final String CANCEL_PROVISIONING_DIALOG_OK 66 = "CancelProvisioningDialogOk"; 67 @VisibleForTesting static final String CANCEL_PROVISIONING_DIALOG_RESET 68 = "CancelProvisioningDialogReset"; 69 70 protected ProvisioningParams mParams; 71 protected @ProvisioningState int mState; 72 73 @VisibleForTesting AbstractProvisioningActivity( Utils utils, SettingsFacade settingsFacade, ThemeHelper themeHelper)74 protected AbstractProvisioningActivity( 75 Utils utils, SettingsFacade settingsFacade, ThemeHelper themeHelper) { 76 super(utils, settingsFacade, themeHelper); 77 } 78 79 // Lazily initialize ProvisioningManager, since we can't call in ProvisioningManager.getInstance 80 // in constructor as base context is not available in constructor. getProvisioningManager()81 protected abstract ProvisioningManagerInterface getProvisioningManager(); 82 // Show the dialog when user press back button while provisioning. decideCancelProvisioningDialog()83 protected abstract void decideCancelProvisioningDialog(); 84 85 @Override onCreate(Bundle savedInstanceState)86 protected void onCreate(Bundle savedInstanceState) { 87 // initialize params so they're accessible for prechecks in onCreate 88 mParams = getIntent().getParcelableExtra(ProvisioningParams.EXTRA_PROVISIONING_PARAMS); 89 super.onCreate(savedInstanceState); 90 91 if (savedInstanceState != null) { 92 mState = savedInstanceState.getInt(KEY_ACTIVITY_STATE, 93 STATE_PROVISIONING_INTIIALIZING); 94 } else { 95 mState = STATE_PROVISIONING_INTIIALIZING; 96 } 97 98 if (mState == STATE_PROVISIONING_INTIIALIZING) { 99 getProvisioningManager().maybeStartProvisioning(mParams); 100 mState = STATE_PROVISIONING_STARTED; 101 } 102 } 103 104 @Override onSaveInstanceState(Bundle outState)105 protected void onSaveInstanceState(Bundle outState) { 106 super.onSaveInstanceState(outState); 107 outState.putInt(KEY_ACTIVITY_STATE, mState); 108 } 109 110 @Override onResume()111 protected void onResume() { 112 super.onResume(); 113 if (!isAnyDialogAdded()) { 114 getProvisioningManager().registerListener(this); 115 } 116 } 117 isAnyDialogAdded()118 private boolean isAnyDialogAdded() { 119 return isDialogAdded(ERROR_DIALOG_OK) 120 || isDialogAdded(ERROR_DIALOG_RESET) 121 || isDialogAdded(CANCEL_PROVISIONING_DIALOG_OK) 122 || isDialogAdded(CANCEL_PROVISIONING_DIALOG_RESET); 123 } 124 125 @Override onPause()126 public void onPause() { 127 getProvisioningManager().unregisterListener(this); 128 super.onPause(); 129 } 130 131 @Override onBackPressed()132 public void onBackPressed() { 133 decideCancelProvisioningDialog(); 134 } 135 showCancelProvisioningDialog(boolean resetRequired)136 protected void showCancelProvisioningDialog(boolean resetRequired) { 137 if (resetRequired) { 138 showDialog(mUtils.createCancelProvisioningResetDialogBuilder(), 139 CANCEL_PROVISIONING_DIALOG_RESET); 140 } else { 141 showDialog(mUtils.createCancelProvisioningDialogBuilder(), 142 CANCEL_PROVISIONING_DIALOG_OK); 143 } 144 } 145 146 @Override error(int titleId, int messageId, boolean resetRequired)147 public void error(int titleId, int messageId, boolean resetRequired) { 148 SimpleDialog.Builder dialogBuilder = new SimpleDialog.Builder() 149 .setTitle(titleId) 150 .setMessage(messageId) 151 .setCancelable(false) 152 .setPositiveButtonMessage(resetRequired 153 ? R.string.reset : android.R.string.ok); 154 155 showDialog(dialogBuilder, resetRequired ? ERROR_DIALOG_RESET : ERROR_DIALOG_OK); 156 } 157 158 @Override showDialog(DialogBuilder builder, String tag)159 protected void showDialog(DialogBuilder builder, String tag) { 160 // Whenever a dialog is shown, stop listening for further updates 161 getProvisioningManager().unregisterListener(this); 162 super.showDialog(builder, tag); 163 } 164 onProvisioningAborted()165 private void onProvisioningAborted() { 166 setResult(Activity.RESULT_CANCELED); 167 getTransitionHelper().finishActivity(this); 168 } 169 170 @Override onNegativeButtonClick(DialogFragment dialog)171 public void onNegativeButtonClick(DialogFragment dialog) { 172 switch (dialog.getTag()) { 173 case CANCEL_PROVISIONING_DIALOG_OK: 174 case CANCEL_PROVISIONING_DIALOG_RESET: 175 dialog.dismiss(); 176 break; 177 default: 178 SimpleDialog.throwButtonClickHandlerNotImplemented(dialog); 179 } 180 getProvisioningManager().registerListener(this); 181 } 182 183 @Override onPositiveButtonClick(DialogFragment dialog)184 public void onPositiveButtonClick(DialogFragment dialog) { 185 switch (dialog.getTag()) { 186 case CANCEL_PROVISIONING_DIALOG_OK: 187 getProvisioningManager().cancelProvisioning(); 188 onProvisioningAborted(); 189 break; 190 case CANCEL_PROVISIONING_DIALOG_RESET: 191 getUtils().factoryReset(this, "Provisioning cancelled by user"); 192 onProvisioningAborted(); 193 break; 194 case ERROR_DIALOG_OK: 195 onProvisioningAborted(); 196 break; 197 case ERROR_DIALOG_RESET: 198 getUtils().factoryReset(this, "Error during provisioning"); 199 onProvisioningAborted(); 200 break; 201 default: 202 SimpleDialog.throwButtonClickHandlerNotImplemented(dialog); 203 } 204 } 205 } 206