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.content.BroadcastReceiver; 27 import android.content.ComponentName; 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 36 import com.android.managedprovisioning.common.Globals; 37 import com.android.managedprovisioning.common.TransitionHelper; 38 import com.android.managedprovisioning.provisioning.ProvisioningService; 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 58 private final BroadcastReceiver mUserUnlockedReceiver = new BroadcastReceiver() { 59 @Override 60 public void onReceive(Context context, Intent intent) { 61 if (!ACTION_USER_UNLOCKED.equals(intent.getAction())) { 62 return; 63 } 64 int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, /* defaultValue= */ -1); 65 UserManager userManager = getSystemService(UserManager.class); 66 if (!userManager.isManagedProfile(userId)) { 67 return; 68 } 69 tryFinalizeProvisioning(); 70 unregisterUserUnlockedReceiver(); 71 } 72 }; 73 FinalizationActivityBase(TransitionHelper transitionHelper)74 FinalizationActivityBase(TransitionHelper transitionHelper) { 75 mTransitionHelper = transitionHelper; 76 } 77 78 @Override onCreate(Bundle savedInstanceState)79 public final void onCreate(Bundle savedInstanceState) { 80 // TODO(b/123987694): Investigate use of buffered i/o for provisioning params file 81 StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() 82 .permitUnbufferedIo() 83 .build()); 84 mTransitionHelper.applyContentScreenTransitions(this); 85 super.onCreate(savedInstanceState); 86 mFinalizationController = createFinalizationController(); 87 88 if (savedInstanceState == null) { 89 getApplicationContext().startService(PROVISIONING_SERVICE_INTENT); 90 } else { 91 final Bundle controllerState = savedInstanceState.getBundle(CONTROLLER_STATE_KEY); 92 if (controllerState != null) { 93 mFinalizationController.restoreInstanceState(controllerState); 94 } 95 96 // If savedInstanceState is not null, we already executed the logic below, so don't do 97 // it again now. We likely just need to wait for a child activity to complete, so we 98 // can execute an onActivityResult() callback before finishing this activity. 99 return; 100 } 101 102 tryFinalizeProvisioning(); 103 } 104 getTransitionHelper()105 protected TransitionHelper getTransitionHelper() { 106 return mTransitionHelper; 107 } 108 tryFinalizeProvisioning()109 private void tryFinalizeProvisioning() { 110 // Register receiver first to avoid race condition when user becomes unlocked after 111 // the user unlocked check. This will be unregistered if we don't need it 112 mIsReceiverRegistered = false; 113 registerUserUnlockedReceiver(); 114 mFinalizationController.provisioningFinalized(); 115 final int result = mFinalizationController.getProvisioningFinalizedResult(); 116 if (PROVISIONING_FINALIZED_RESULT_CHILD_ACTIVITY_LAUNCHED == result) { 117 onFinalizationCompletedWithChildActivityLaunched(); 118 } else if (PROVISIONING_FINALIZED_RESULT_WAIT_FOR_WORK_PROFILE_AVAILABLE != result) { 119 if (FinalizationController.PROVISIONING_FINALIZED_RESULT_SKIPPED != result) { 120 mFinalizationController.commitFinalizedState(); 121 } 122 setResult(RESULT_OK); 123 getTransitionHelper().finishActivity(this); 124 } 125 126 if (PROVISIONING_FINALIZED_RESULT_WAIT_FOR_WORK_PROFILE_AVAILABLE != result) { 127 unregisterUserUnlockedReceiver(); 128 } 129 } 130 registerUserUnlockedReceiver()131 private void registerUserUnlockedReceiver() { 132 IntentFilter filter = new IntentFilter(); 133 filter.addAction(ACTION_USER_UNLOCKED); 134 registerReceiverAsUser( 135 mUserUnlockedReceiver, 136 UserHandle.ALL, 137 filter, 138 /* broadcastPermission= */ null, 139 /* scheduler= */ null); 140 mIsReceiverRegistered = true; 141 } 142 unregisterUserUnlockedReceiver()143 private void unregisterUserUnlockedReceiver() { 144 if (!mIsReceiverRegistered) { 145 return; 146 } 147 unregisterReceiver(mUserUnlockedReceiver); 148 mIsReceiverRegistered = false; 149 } 150 151 @Override onSaveInstanceState(Bundle outState)152 protected final void onSaveInstanceState(Bundle outState) { 153 super.onSaveInstanceState(outState); 154 155 final Bundle controllerState = new Bundle(); 156 outState.putBundle(CONTROLLER_STATE_KEY, controllerState); 157 mFinalizationController.saveInstanceState(controllerState); 158 } 159 160 @Override onDestroy()161 public final void onDestroy() { 162 mFinalizationController.activityDestroyed(isFinishing()); 163 unregisterUserUnlockedReceiver(); 164 getApplicationContext().stopService(PROVISIONING_SERVICE_INTENT); 165 super.onDestroy(); 166 } 167 168 /** 169 * Return the finalization controller instance that was constructed in {@link #onCreate}. 170 */ getFinalizationController()171 protected FinalizationController getFinalizationController() { 172 return mFinalizationController; 173 } 174 175 /** 176 * Construct the correct subtype of FinalizationController. 177 */ createFinalizationController()178 protected abstract FinalizationController createFinalizationController(); 179 180 /** 181 * Hook for code that should run when the controller has launched a child activity. 182 */ onFinalizationCompletedWithChildActivityLaunched()183 protected abstract void onFinalizationCompletedWithChildActivityLaunched(); 184 } 185