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.content.Intent.ACTION_USER_UNLOCKED; 20 21 import static com.android.managedprovisioning.finalization.FinalizationController.PROVISIONING_FINALIZED_RESULT_CHILD_ACTIVITY_LAUNCHED; 22 import static com.android.managedprovisioning.finalization.FinalizationController.PROVISIONING_FINALIZED_RESULT_WAIT_FOR_WORK_PROFILE_AVAILABLE; 23 import static com.android.managedprovisioning.provisioning.Constants.PROVISIONING_SERVICE_INTENT; 24 25 import android.app.Activity; 26 import android.app.BackgroundServiceStartNotAllowedException; 27 import android.content.BroadcastReceiver; 28 import android.content.Context; 29 import android.content.Intent; 30 import android.content.IntentFilter; 31 import android.os.Bundle; 32 import android.os.StrictMode; 33 import android.os.UserHandle; 34 import android.os.UserManager; 35 import android.view.WindowManager; 36 37 import com.android.managedprovisioning.common.ProvisionLogger; 38 import com.android.managedprovisioning.common.TransitionHelper; 39 40 /** 41 * Instances of this base class manage interactions with a Device Policy Controller app after it has 42 * been set up as either a Device Owner or a Profile Owner. 43 * 44 * Once we are sure that the DPC app has had an opportunity to run its own setup activities, we 45 * record in the system that provisioning has been finalized. 46 * 47 * Different instances of this class will be tailored to run at different points in the Setup 48 * Wizard user flows. 49 */ 50 public abstract class FinalizationActivityBase extends Activity { 51 52 private static final String CONTROLLER_STATE_KEY = "controller_state"; 53 54 private final TransitionHelper mTransitionHelper; 55 private FinalizationController mFinalizationController; 56 private boolean mIsReceiverRegistered; 57 private boolean mRestoring; 58 59 private final BroadcastReceiver mUserUnlockedReceiver = new BroadcastReceiver() { 60 @Override 61 public void onReceive(Context context, Intent intent) { 62 if (!ACTION_USER_UNLOCKED.equals(intent.getAction())) { 63 return; 64 } 65 int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, /* defaultValue= */ -1); 66 UserManager userManager = getSystemService(UserManager.class); 67 if (!userManager.isManagedProfile(userId)) { 68 return; 69 } 70 tryFinalizeProvisioning(); 71 unregisterUserUnlockedReceiver(); 72 } 73 }; 74 FinalizationActivityBase(TransitionHelper transitionHelper)75 FinalizationActivityBase(TransitionHelper transitionHelper) { 76 mTransitionHelper = transitionHelper; 77 } 78 79 @Override onCreate(Bundle savedInstanceState)80 public final void onCreate(Bundle savedInstanceState) { 81 // TODO(b/123987694): Investigate use of buffered i/o for provisioning params file 82 StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() 83 .permitUnbufferedIo() 84 .build()); 85 mTransitionHelper.applyContentScreenTransitions(this); 86 super.onCreate(savedInstanceState); 87 getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 88 89 mFinalizationController = createFinalizationController(); 90 91 mRestoring = savedInstanceState != null; 92 if (mRestoring) { 93 final Bundle controllerState = savedInstanceState.getBundle(CONTROLLER_STATE_KEY); 94 if (controllerState != null) { 95 mFinalizationController.restoreInstanceState(controllerState); 96 } 97 98 // If savedInstanceState is not null, we already executed the logic below, so don't do 99 // it again now. We likely just need to wait for a child activity to complete, so we 100 // can execute an onActivityResult() callback before finishing this activity. 101 return; 102 } 103 } 104 105 @Override onStart()106 protected void onStart() { 107 super.onStart(); 108 try { 109 getApplicationContext().startService(PROVISIONING_SERVICE_INTENT); 110 } catch (BackgroundServiceStartNotAllowedException e) { 111 ProvisionLogger.loge(e); 112 } 113 if (!mRestoring) { 114 tryFinalizeProvisioning(); 115 } 116 } 117 getTransitionHelper()118 protected TransitionHelper getTransitionHelper() { 119 return mTransitionHelper; 120 } 121 tryFinalizeProvisioning()122 private void tryFinalizeProvisioning() { 123 // Register receiver first to avoid race condition when user becomes unlocked after 124 // the user unlocked check. This will be unregistered if we don't need it 125 mIsReceiverRegistered = false; 126 registerUserUnlockedReceiver(); 127 mFinalizationController.provisioningFinalized(); 128 final int result = mFinalizationController.getProvisioningFinalizedResult(); 129 if (PROVISIONING_FINALIZED_RESULT_CHILD_ACTIVITY_LAUNCHED == result) { 130 onFinalizationCompletedWithChildActivityLaunched(); 131 } else if (PROVISIONING_FINALIZED_RESULT_WAIT_FOR_WORK_PROFILE_AVAILABLE != result) { 132 if (FinalizationController.PROVISIONING_FINALIZED_RESULT_SKIPPED != result) { 133 mFinalizationController.commitFinalizedState(); 134 } 135 setResult(RESULT_OK); 136 getTransitionHelper().finishActivity(this); 137 } 138 139 if (PROVISIONING_FINALIZED_RESULT_WAIT_FOR_WORK_PROFILE_AVAILABLE != result) { 140 unregisterUserUnlockedReceiver(); 141 } 142 } 143 registerUserUnlockedReceiver()144 private void registerUserUnlockedReceiver() { 145 IntentFilter filter = new IntentFilter(); 146 filter.addAction(ACTION_USER_UNLOCKED); 147 registerReceiverAsUser( 148 mUserUnlockedReceiver, 149 UserHandle.ALL, 150 filter, 151 /* broadcastPermission= */ null, 152 /* scheduler= */ null); 153 mIsReceiverRegistered = true; 154 } 155 unregisterUserUnlockedReceiver()156 private void unregisterUserUnlockedReceiver() { 157 if (!mIsReceiverRegistered) { 158 return; 159 } 160 unregisterReceiver(mUserUnlockedReceiver); 161 mIsReceiverRegistered = false; 162 } 163 164 @Override onSaveInstanceState(Bundle outState)165 protected final void onSaveInstanceState(Bundle outState) { 166 super.onSaveInstanceState(outState); 167 168 final Bundle controllerState = new Bundle(); 169 outState.putBundle(CONTROLLER_STATE_KEY, controllerState); 170 mFinalizationController.saveInstanceState(controllerState); 171 } 172 173 @Override onDestroy()174 public final void onDestroy() { 175 mFinalizationController.activityDestroyed(isFinishing()); 176 unregisterUserUnlockedReceiver(); 177 getApplicationContext().stopService(PROVISIONING_SERVICE_INTENT); 178 super.onDestroy(); 179 } 180 181 /** 182 * Return the finalization controller instance that was constructed in {@link #onCreate}. 183 */ getFinalizationController()184 protected FinalizationController getFinalizationController() { 185 return mFinalizationController; 186 } 187 188 /** 189 * Construct the correct subtype of FinalizationController. 190 */ createFinalizationController()191 protected abstract FinalizationController createFinalizationController(); 192 193 /** 194 * Hook for code that should run when the controller has launched a child activity. 195 */ onFinalizationCompletedWithChildActivityLaunched()196 protected abstract void onFinalizationCompletedWithChildActivityLaunched(); 197 } 198