1 /*
2  * Copyright (C) 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.common;
18 
19 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE;
20 
21 import static com.android.managedprovisioning.provisioning.Constants.EXTRA_PROVISIONING_COLOR_PALETTE;
22 
23 import android.app.Activity;
24 import android.app.admin.DevicePolicyManager;
25 import android.content.Context;
26 import android.content.Intent;
27 import android.os.UserHandle;
28 
29 import com.android.managedprovisioning.analytics.ProvisioningAnalyticsTracker;
30 import com.android.managedprovisioning.model.ProvisioningParams;
31 
32 import com.google.android.setupcompat.util.WizardManagerHelper;
33 
34 import java.util.HashMap;
35 import java.util.function.BiConsumer;
36 
37 /**
38  * Class containing utility methods for starting up a DPC during Setup Wizard.
39  */
40 public class PolicyComplianceUtils {
41 
42     /**
43      * Returns whether the DPC handles the policy compliance activity on the managed user.
44      */
isPolicyComplianceActivityResolvableForManagedUser( Context context, ProvisioningParams params, Utils utils)45     public boolean isPolicyComplianceActivityResolvableForManagedUser(
46             Context context, ProvisioningParams params, Utils utils) {
47         UserHandle userHandle = getPolicyComplianceUserHandle(context, params, utils);
48         return getPolicyComplianceIntentIfResolvable(context, params, utils, userHandle) != null;
49     }
50 
51     /**
52      * Returns whether the DPC handles the policy compliance activity on a given user.
53      */
isPolicyComplianceActivityResolvableForUser( Context context, ProvisioningParams params, Utils utils, UserHandle userHandle)54     public boolean isPolicyComplianceActivityResolvableForUser(
55             Context context, ProvisioningParams params, Utils utils, UserHandle userHandle) {
56         return getPolicyComplianceIntentIfResolvable(context, params, utils, userHandle) != null;
57     }
58 
59     /**
60      * Starts the policy compliance activity if it can be resolved, and returns whether the
61      * activity was started.
62      */
startPolicyComplianceActivityForResultIfResolved(Activity parentActivity, ProvisioningParams params, int requestCode, Utils utils, ProvisioningAnalyticsTracker provisioningAnalyticsTracker, TransitionHelper transitionHelper)63     public boolean startPolicyComplianceActivityForResultIfResolved(Activity parentActivity,
64             ProvisioningParams params, int requestCode, Utils utils,
65             ProvisioningAnalyticsTracker provisioningAnalyticsTracker,
66             TransitionHelper transitionHelper) {
67         return startPolicyComplianceActivityIfResolvedInternal(parentActivity, params, utils,
68                 provisioningAnalyticsTracker, (Intent intent, UserHandle userHandle) -> {
69                     if (parentActivity.getIntent() != null) {
70                         WizardManagerHelper.copyWizardManagerExtras(
71                                 parentActivity.getIntent(), intent);
72                     }
73                     transitionHelper.startActivityForResultAsUserWithTransition(
74                             parentActivity, intent, requestCode, userHandle);
75                 });
76     }
77 
78     /**
79      * Starts the policy compliance activity if it can be resolved, and returns whether the
80      * activity was started.
81      */
82     public boolean startPolicyComplianceActivityIfResolved(Context context,
83             ProvisioningParams params, Utils utils,
84             ProvisioningAnalyticsTracker provisioningAnalyticsTracker) {
85         return startPolicyComplianceActivityIfResolvedInternal(
86                 context,
87                 params,
88                 utils,
89                 provisioningAnalyticsTracker,
90                 context::startActivityAsUser);
91     }
92 
93     private boolean startPolicyComplianceActivityIfResolvedInternal(
94             Context context, ProvisioningParams params, Utils utils,
95             ProvisioningAnalyticsTracker provisioningAnalyticsTracker,
96             BiConsumer<Intent, UserHandle> startActivityFunc) {
97         final UserHandle userHandle = getPolicyComplianceUserHandle(context, params, utils);
98         final Intent policyComplianceIntent = getPolicyComplianceIntentIfResolvable(
99                 context, params, utils, userHandle);
100 
101         if (policyComplianceIntent != null) {
102             startActivityFunc.accept(policyComplianceIntent, userHandle);
103             ProvisionLogger.logd(
104                     "The DPC POLICY_COMPLIANCE handler was launched on user " + userHandle);
105             provisioningAnalyticsTracker.logDpcSetupStarted(
106                     context, policyComplianceIntent.getAction());
107             return true;
108         }
109 
110         return false;
111     }
112 
113     private Intent getPolicyComplianceIntentIfResolvable(Context context,
114             ProvisioningParams params, Utils utils, UserHandle userHandle) {
115         final Intent policyComplianceIntent = getPolicyComplianceIntent(params, context);
116         final boolean intentResolvable = utils.canResolveIntentAsUser(context,
117                 policyComplianceIntent, userHandle.getIdentifier());
118         // Calling startActivity() from outside of an Activity context requires
119         // the FLAG_ACTIVITY_NEW_TASK flag.
120         if (!(context instanceof Activity)) {
121             policyComplianceIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
122         }
123         return intentResolvable ? policyComplianceIntent : null;
124     }
125 
126     private Intent getPolicyComplianceIntent(
127             ProvisioningParams params, Context context) {
128         final String adminPackage = params.inferDeviceAdminPackageName();
129         final Intent policyComplianceIntent =
130                 new Intent(DevicePolicyManager.ACTION_ADMIN_POLICY_COMPLIANCE);
131         policyComplianceIntent.putExtra(
132                 DevicePolicyManager.EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE,
133                 params.adminExtrasBundle);
134         // TODO(b/192254845): Remove EXTRA_PROVISIONING_COLOR_PALETTE when framework
135         //  fix available
136         HashMap<Integer, Integer> colorPaletteMap =
137                 new ColorPaletteHelper().createColorPaletteMap(
138                         context,
139                         new ManagedProvisioningSharedPreferences(context));
140         policyComplianceIntent.putExtra(EXTRA_PROVISIONING_COLOR_PALETTE, colorPaletteMap);
141         policyComplianceIntent.setPackage(adminPackage);
142         return policyComplianceIntent;
143     }
144 
145     private UserHandle getPolicyComplianceUserHandle(Context context,
146             ProvisioningParams params, Utils utils) {
147         return params.provisioningAction.equals(ACTION_PROVISION_MANAGED_PROFILE)
148                 ? utils.getManagedProfile(context)
149                 : UserHandle.of(UserHandle.myUserId());
150     }
151 }
152