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 com.android.managedprovisioning.finalization.FinalizationController.PROVISIONING_FINALIZED_RESULT_CHILD_ACTIVITY_LAUNCHED;
20 import static com.android.managedprovisioning.finalization.FinalizationController.PROVISIONING_FINALIZED_RESULT_NO_CHILD_ACTIVITY_LAUNCHED;
21 import static com.android.managedprovisioning.finalization.FinalizationController.ProvisioningFinalizedResult;
22 
23 import android.app.Activity;
24 import android.os.Bundle;
25 import android.os.UserHandle;
26 
27 import com.android.managedprovisioning.analytics.MetricsWriterFactory;
28 import com.android.managedprovisioning.analytics.ProvisioningAnalyticsTracker;
29 import com.android.managedprovisioning.common.ManagedProvisioningSharedPreferences;
30 import com.android.managedprovisioning.common.PolicyComplianceUtils;
31 import com.android.managedprovisioning.common.ProvisionLogger;
32 import com.android.managedprovisioning.common.SettingsFacade;
33 import com.android.managedprovisioning.common.StartDpcInsideSuwServiceConnection;
34 import com.android.managedprovisioning.common.TransitionHelper;
35 import com.android.managedprovisioning.common.Utils;
36 import com.android.managedprovisioning.model.ProvisioningParams;
37 
38 /**
39  * This controller is used to finalize managed provisioning before the end of Setup Wizard.
40  */
41 public class FinalizationInsideSuwControllerLogic implements FinalizationControllerLogic {
42     private static final String START_DPC_SERVICE_STATE_KEY = "start_dpc_service_state";
43     private static final String LAST_REQUEST_CODE_KEY = "last_request_code";
44 
45     private final Activity mActivity;
46     private final Utils mUtils;
47     private final PolicyComplianceUtils mPolicyComplianceUtils;
48     private final ProvisioningAnalyticsTracker mProvisioningAnalyticsTracker;
49     private final TransitionHelper mTransitionHelper;
50     private StartDpcInsideSuwServiceConnection mStartDpcInsideSuwServiceConnection;
51     private int mLastRequestCode = 0;
52 
FinalizationInsideSuwControllerLogic(Activity activity)53     public FinalizationInsideSuwControllerLogic(Activity activity) {
54         this(activity, new Utils(), new PolicyComplianceUtils(),
55                 new ProvisioningAnalyticsTracker(
56                         MetricsWriterFactory.getMetricsWriter(activity, new SettingsFacade()),
57                         new ManagedProvisioningSharedPreferences(activity)),
58                 new TransitionHelper());
59     }
60 
FinalizationInsideSuwControllerLogic(Activity activity, Utils utils, PolicyComplianceUtils policyComplianceUtils, ProvisioningAnalyticsTracker provisioningAnalyticsTracker, TransitionHelper transitionHelper)61     public FinalizationInsideSuwControllerLogic(Activity activity, Utils utils,
62             PolicyComplianceUtils policyComplianceUtils,
63             ProvisioningAnalyticsTracker provisioningAnalyticsTracker,
64             TransitionHelper transitionHelper) {
65         mActivity = activity;
66         mUtils = utils;
67         mPolicyComplianceUtils = policyComplianceUtils;
68         mProvisioningAnalyticsTracker = provisioningAnalyticsTracker;
69         mTransitionHelper = transitionHelper;
70     }
71 
72     @Override
notifyDpcManagedProfile( ProvisioningParams params, int requestCode)73     public @ProvisioningFinalizedResult int notifyDpcManagedProfile(
74             ProvisioningParams params, int requestCode) {
75         return startPolicyComplianceActivityForResultIfResolved(params, requestCode);
76     }
77 
78     @Override
notifyDpcManagedDeviceOrUser( ProvisioningParams params, int requestCode)79     public @ProvisioningFinalizedResult int notifyDpcManagedDeviceOrUser(
80             ProvisioningParams params, int requestCode) {
81         return startPolicyComplianceActivityForResultIfResolved(params, requestCode);
82     }
83 
84     @Override
shouldFinalizePrimaryProfile(ProvisioningParams params)85     public boolean shouldFinalizePrimaryProfile(ProvisioningParams params) {
86         return true;
87     }
88 
89     @Override
saveInstanceState(Bundle outState)90     public void saveInstanceState(Bundle outState) {
91         outState.putInt(LAST_REQUEST_CODE_KEY, mLastRequestCode);
92 
93         if (mStartDpcInsideSuwServiceConnection != null) {
94             final Bundle startDpcServiceState = new Bundle();
95             outState.putBundle(START_DPC_SERVICE_STATE_KEY, startDpcServiceState);
96             mStartDpcInsideSuwServiceConnection.saveInstanceState(startDpcServiceState);
97         }
98     }
99 
100     @Override
restoreInstanceState(Bundle savedInstanceState, ProvisioningParams params)101     public void restoreInstanceState(Bundle savedInstanceState, ProvisioningParams params) {
102         mLastRequestCode = savedInstanceState.getInt(LAST_REQUEST_CODE_KEY);
103 
104         final Bundle startDpcServiceState =
105                 savedInstanceState.getBundle(START_DPC_SERVICE_STATE_KEY);
106 
107         if (startDpcServiceState != null) {
108             mStartDpcInsideSuwServiceConnection = new StartDpcInsideSuwServiceConnection(
109                     mActivity,
110                     startDpcServiceState,
111                     getDpcIntentSender(params, mLastRequestCode));
112         }
113     }
114 
115     @Override
activityDestroyed(boolean isFinishing)116     public void activityDestroyed(boolean isFinishing) {
117         if (mStartDpcInsideSuwServiceConnection != null) {
118             if (isFinishing) {
119                 mStartDpcInsideSuwServiceConnection.dpcFinished();
120             }
121 
122             mStartDpcInsideSuwServiceConnection.unbind(mActivity);
123 
124             if (isFinishing) {
125                 mStartDpcInsideSuwServiceConnection = null;
126             }
127         }
128     }
129 
startPolicyComplianceActivityForResultIfResolved( ProvisioningParams params, int requestCode)130     private @ProvisioningFinalizedResult int startPolicyComplianceActivityForResultIfResolved(
131             ProvisioningParams params, int requestCode) {
132         if (!mPolicyComplianceUtils.isPolicyComplianceActivityResolvableForManagedUser(
133                 mActivity, params, mUtils)) {
134             return PROVISIONING_FINALIZED_RESULT_NO_CHILD_ACTIVITY_LAUNCHED;
135         }
136 
137         if (mStartDpcInsideSuwServiceConnection != null) {
138             ProvisionLogger.logw("Attempted to start DPC again before result received - ignoring");
139             return PROVISIONING_FINALIZED_RESULT_NO_CHILD_ACTIVITY_LAUNCHED;
140         }
141 
142         // Connect to a SUW service to disable network intent interception before starting the DPC.
143         mStartDpcInsideSuwServiceConnection = new StartDpcInsideSuwServiceConnection();
144         mStartDpcInsideSuwServiceConnection.triggerDpcStart(mActivity,
145                 getDpcIntentSender(params, requestCode));
146 
147         mLastRequestCode = requestCode;
148 
149         return PROVISIONING_FINALIZED_RESULT_CHILD_ACTIVITY_LAUNCHED;
150     }
151 
getDpcIntentSender(ProvisioningParams params, int requestCode)152     private Runnable getDpcIntentSender(ProvisioningParams params, int requestCode) {
153         return () ->
154                 mPolicyComplianceUtils.startPolicyComplianceActivityForResultIfResolved(
155                         mActivity, params, requestCode, mUtils, mProvisioningAnalyticsTracker,
156                         mTransitionHelper);
157     }
158 }
159