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