1 /*
2  * Copyright 2018, 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.app.admin.DeviceAdminReceiver.ACTION_PROFILE_PROVISIONING_COMPLETE;
20 import static android.app.admin.DevicePolicyManager.ACTION_PROVISIONING_SUCCESSFUL;
21 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE;
22 import static android.app.admin.DevicePolicyManager.PROVISIONING_TRIGGER_UNSPECIFIED;
23 
24 import static com.android.managedprovisioning.model.ProvisioningParams.FLOW_TYPE_ADMIN_INTEGRATED;
25 import static com.android.managedprovisioning.provisioning.Constants.EXTRA_PROVISIONING_COLOR_PALETTE;
26 
27 import android.annotation.NonNull;
28 import android.content.Context;
29 import android.content.Intent;
30 import android.os.UserHandle;
31 
32 import com.android.managedprovisioning.analytics.ProvisioningAnalyticsTracker;
33 import com.android.managedprovisioning.common.ColorPaletteHelper;
34 import com.android.managedprovisioning.common.IllegalProvisioningArgumentException;
35 import com.android.managedprovisioning.common.ManagedProvisioningSharedPreferences;
36 import com.android.managedprovisioning.common.PolicyComplianceUtils;
37 import com.android.managedprovisioning.common.ProvisionLogger;
38 import com.android.managedprovisioning.common.SettingsFacade;
39 import com.android.managedprovisioning.common.Utils;
40 import com.android.managedprovisioning.model.ProvisioningParams;
41 
42 import java.util.HashMap;
43 
44 /**
45  * Helper class for creating intents in finalization controller.
46  */
47 class ProvisioningIntentProvider {
maybeLaunchDpc(ProvisioningParams params, int userId, Utils utils, Context context, ProvisioningAnalyticsTracker provisioningAnalyticsTracker, PolicyComplianceUtils policyComplianceUtils, SettingsFacade settingsFacade)48     void maybeLaunchDpc(ProvisioningParams params, int userId, Utils utils, Context context,
49             ProvisioningAnalyticsTracker provisioningAnalyticsTracker,
50             PolicyComplianceUtils policyComplianceUtils,
51             SettingsFacade settingsFacade) {
52         if (shouldLaunchPolicyCompliance(
53                 context, settingsFacade, params, policyComplianceUtils, utils, userId)) {
54             launchPolicyComplianceDpcHandler(
55                     context, params, utils, provisioningAnalyticsTracker, policyComplianceUtils);
56         } else {
57             launchProvisioningSuccessfulDpcHandler(
58                     params, userId, utils, context, provisioningAnalyticsTracker);
59         }
60     }
61 
62     // TODO(b/184855881): Make manually-installed-and-started-DPC provisioning use the
63     // policy compliance screen. Then here we will only check if we're doing the admin-integrated
64     // flow.
shouldLaunchPolicyCompliance( Context context, SettingsFacade settingsFacade, ProvisioningParams params, PolicyComplianceUtils policyComplianceUtils, Utils utils, int userId)65     private boolean shouldLaunchPolicyCompliance(
66             Context context, SettingsFacade settingsFacade, ProvisioningParams params,
67             PolicyComplianceUtils policyComplianceUtils, Utils utils, int userId) {
68         // If we're performing the admin-integrated flow, we've already validated that
69         // the policy compliance handler exists.
70         if (params.flowType == FLOW_TYPE_ADMIN_INTEGRATED) {
71             return true;
72         }
73         if (!policyComplianceUtils.isPolicyComplianceActivityResolvableForUser(
74                 context, params, utils, UserHandle.of(userId))) {
75             return false;
76         }
77         // TODO(b/184933215): Remove logic specific to legacy managed account provisioning
78         if (params.provisioningTrigger != PROVISIONING_TRIGGER_UNSPECIFIED) {
79             return false;
80         }
81         return settingsFacade.isDuringSetupWizard(context);
82     }
83 
launchPolicyComplianceDpcHandler( Context context, ProvisioningParams params, Utils utils, ProvisioningAnalyticsTracker provisioningAnalyticsTracker, PolicyComplianceUtils policyComplianceUtils)84     private void launchPolicyComplianceDpcHandler(
85             Context context, ProvisioningParams params, Utils utils,
86             ProvisioningAnalyticsTracker provisioningAnalyticsTracker,
87             PolicyComplianceUtils policyComplianceUtils) {
88         policyComplianceUtils.startPolicyComplianceActivityIfResolved(
89                 context, params, utils, provisioningAnalyticsTracker);
90     }
91 
launchProvisioningSuccessfulDpcHandler(ProvisioningParams params, int userId, Utils utils, Context context, ProvisioningAnalyticsTracker provisioningAnalyticsTracker)92     private void launchProvisioningSuccessfulDpcHandler(ProvisioningParams params, int userId,
93             Utils utils, Context context,
94             ProvisioningAnalyticsTracker provisioningAnalyticsTracker) {
95         final Intent dpcLaunchIntent = createDpcLaunchIntent(params, context, utils);
96         if (utils.canResolveIntentAsUser(context, dpcLaunchIntent, userId)) {
97             context.startActivityAsUser(
98                     createDpcLaunchIntent(params, context, utils), UserHandle.of(userId));
99             ProvisionLogger.logd("Dpc was launched for user: " + userId);
100             provisioningAnalyticsTracker.logDpcSetupStarted(context, dpcLaunchIntent.getAction());
101         }
102     }
103 
canLaunchDpc(ProvisioningParams params, int userId, Utils utils, Context context)104     boolean canLaunchDpc(ProvisioningParams params, int userId, Utils utils, Context context) {
105         final Intent dpcLaunchIntent = createDpcLaunchIntent(params, context, utils);
106         return utils.canResolveIntentAsUser(context, dpcLaunchIntent, userId);
107     }
108 
createProvisioningCompleteIntent( @onNull ProvisioningParams params, int userId, Utils utils, Context context)109     Intent createProvisioningCompleteIntent(
110             @NonNull ProvisioningParams params, int userId, Utils utils, Context context) {
111         Intent intent = new Intent(ACTION_PROFILE_PROVISIONING_COMPLETE);
112         try {
113             intent.setComponent(params.inferDeviceAdminComponentName(utils, context, userId));
114         } catch (IllegalProvisioningArgumentException e) {
115             ProvisionLogger.loge("Failed to infer the device admin component name", e);
116             return null;
117         }
118         intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES | Intent.FLAG_RECEIVER_FOREGROUND);
119         addExtrasToIntent(intent, params, context);
120         return intent;
121     }
122 
createDpcLaunchIntent( @onNull ProvisioningParams params, Context context, Utils utils)123     private Intent createDpcLaunchIntent(
124             @NonNull ProvisioningParams params, Context context, Utils utils) {
125         Intent intent = new Intent(ACTION_PROVISIONING_SUCCESSFUL);
126         final String packageName = params.inferDeviceAdminPackageName();
127         if (packageName == null) {
128             ProvisionLogger.loge("Device admin package name is null");
129             return null;
130         }
131         intent.setPackage(packageName);
132         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
133         addExtrasToIntent(intent, params, context);
134         return intent;
135     }
136 
addExtrasToIntent(Intent intent, ProvisioningParams params, Context context)137     private void addExtrasToIntent(Intent intent, ProvisioningParams params,
138             Context context) {
139         intent.putExtra(EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE, params.adminExtrasBundle);
140         // TODO(b/192254845): Remove EXTRA_PROVISIONING_COLOR_PALETTE when framework
141         //  fix available
142         HashMap<Integer, Integer> colorPaletteMap =
143                 new ColorPaletteHelper().createColorPaletteMap(
144                         context,
145                         new ManagedProvisioningSharedPreferences(context));
146         intent.putExtra(EXTRA_PROVISIONING_COLOR_PALETTE, colorPaletteMap);
147     }
148 }
149