• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2017, 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 package com.android.managedprovisioning.preprovisioning.terms;
17 
18 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DISCLAIMER_CONTENT;
19 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DISCLAIMER_HEADER;
20 import static android.content.pm.PackageManager.GET_META_DATA;
21 import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
22 
23 import android.annotation.IntDef;
24 import android.app.admin.DevicePolicyManager;
25 import android.content.Context;
26 import android.content.pm.ApplicationInfo;
27 import android.content.pm.PackageManager;
28 import android.content.res.Resources;
29 import com.android.managedprovisioning.R;
30 import com.android.managedprovisioning.common.ProvisionLogger;
31 import com.android.managedprovisioning.common.StoreUtils;
32 import com.android.managedprovisioning.common.Utils;
33 import com.android.managedprovisioning.model.DisclaimersParam;
34 import com.android.managedprovisioning.model.ProvisioningParams;
35 import java.io.File;
36 import java.io.IOException;
37 import java.lang.annotation.Retention;
38 import java.lang.annotation.RetentionPolicy;
39 import java.util.ArrayList;
40 import java.util.List;
41 import java.util.Objects;
42 import java.util.stream.Collectors;
43 
44 /**
45  * Sources all available {@link TermsDocument}s:
46  * <ul>
47  * <li> hardcoded 'General' terms,
48  * <li> terms exposed via installed apps,
49  * <li> terms passed from DPC.
50  * </ul>
51  */
52 public class TermsProvider {
53     private final Context mContext;
54     private final StoreUtils.TextFileReader mTextFileReader;
55     private final Utils mUtils;
56 
57     /**
58      * Sources all available {@link TermsDocument}s:
59      * <ul>
60      * <li> hardcoded 'General' terms,
61      * <li> terms exposed via installed apps,
62      * <li> terms passed from DPC.
63      * </ul>
64      */
TermsProvider(Context context, StoreUtils.TextFileReader textFileReader, Utils utils)65     public TermsProvider(Context context, StoreUtils.TextFileReader textFileReader, Utils utils) {
66         mContext = context;
67         mTextFileReader = textFileReader;
68         mUtils = utils;
69     }
70 
71     /**
72      * Sources all available {@link TermsDocument}s:
73      * <ul>
74      * <li> hardcoded 'General' terms,
75      * <li> terms exposed via installed apps,
76      * <li> terms passed from DPC.
77      * </ul>
78      */
getTerms(ProvisioningParams params, @Flags int flags)79     public List<TermsDocument> getTerms(ProvisioningParams params, @Flags int flags) {
80         List<TermsDocument> result = new ArrayList<>();
81         int provisioningCase = determineProvisioningCase(params);
82 
83         if ((flags & Flags.SKIP_GENERAL_DISCLAIMER) == 0) {
84             result.add(getGeneralDisclaimer(provisioningCase));
85         }
86 
87         if (provisioningCase == ProvisioningCase.DEVICE_OWNER) {
88             result.addAll(getSystemAppTerms());
89         }
90 
91         result.addAll(getExtraDisclaimers(params));
92 
93         return result.stream().filter(Objects::nonNull).collect(Collectors.toList());
94     }
95 
determineProvisioningCase(ProvisioningParams params)96     private int determineProvisioningCase(ProvisioningParams params) {
97         if (mUtils.isDeviceOwnerAction(params.provisioningAction)) {
98             return ProvisioningCase.DEVICE_OWNER;
99         }
100 
101         // TODO: move somewhere more general
102         boolean isComp = ((DevicePolicyManager) mContext
103             .getSystemService(Context.DEVICE_POLICY_SERVICE)).isDeviceManaged();
104 
105         return isComp ? ProvisioningCase.COMP : ProvisioningCase.PROFILE_OWNER;
106     }
107 
getGeneralDisclaimer(@rovisioningCase int provisioningCase)108     private TermsDocument getGeneralDisclaimer(@ProvisioningCase int provisioningCase) {
109         String heading = mContext.getString(provisioningCase == ProvisioningCase.PROFILE_OWNER
110             ? R.string.work_profile_info
111             : R.string.managed_device_info);
112         String content = mContext.getString(provisioningCase == ProvisioningCase.PROFILE_OWNER
113                 ? R.string.admin_has_ability_to_monitor_profile
114                 : R.string.admin_has_ability_to_monitor_device);
115         return TermsDocument.createInstance(heading, content);
116     }
117 
getSystemAppTerms()118     private List<TermsDocument> getSystemAppTerms() {
119         List<TermsDocument> terms = new ArrayList<>();
120         List<ApplicationInfo> appInfos = mContext.getPackageManager().getInstalledApplications(
121                 MATCH_SYSTEM_ONLY | GET_META_DATA);
122         for (ApplicationInfo appInfo : appInfos) {
123             String header = getStringMetaData(appInfo, EXTRA_PROVISIONING_DISCLAIMER_HEADER);
124             String content = getStringMetaData(appInfo, EXTRA_PROVISIONING_DISCLAIMER_CONTENT);
125             if (header != null && content != null) {
126                 terms.add(TermsDocument.createInstance(header, content));
127             }
128         }
129         return terms;
130     }
131 
getExtraDisclaimers(ProvisioningParams params)132     private List<TermsDocument> getExtraDisclaimers(ProvisioningParams params) {
133         List<TermsDocument> result = new ArrayList<>();
134 
135         DisclaimersParam.Disclaimer[] disclaimers = params.disclaimersParam == null ? null
136                 : params.disclaimersParam.mDisclaimers;
137         if (disclaimers != null) {
138             for (DisclaimersParam.Disclaimer disclaimer : disclaimers) {
139                 try {
140                     String htmlContent = mTextFileReader.read(
141                             new File(disclaimer.mContentFilePath));
142                     result.add(TermsDocument.createInstance(disclaimer.mHeader, htmlContent));
143                 } catch (IOException e) {
144                     ProvisionLogger.loge("Failed to read disclaimer", e);
145                 }
146             }
147         }
148 
149         return result;
150     }
151 
getStringMetaData(ApplicationInfo appInfo, String key)152     private String getStringMetaData(ApplicationInfo appInfo, String key) {
153         if (appInfo.metaData != null) {
154             int resId = appInfo.metaData.getInt(key);
155             if (resId != 0) {
156                 try {
157                     return mContext.getPackageManager().getResourcesForApplication(
158                             appInfo).getString(resId);
159                 } catch (PackageManager.NameNotFoundException | Resources.NotFoundException e) {
160                     ProvisionLogger.loge("NameNotFoundException", e);
161                 }
162             }
163         }
164         return null;
165     }
166 
167     // TODO: move somewhere more general
168     @IntDef(value = {
169             ProvisioningCase.PROFILE_OWNER,
170             ProvisioningCase.DEVICE_OWNER,
171             ProvisioningCase.COMP,
172     })
173     @Retention(RetentionPolicy.SOURCE)
174     private @interface ProvisioningCase {
175         int PROFILE_OWNER = 1;
176         int DEVICE_OWNER = 2;
177         int COMP = 4;
178     }
179 
180     @IntDef(flag = true, value = {
181             Flags.SKIP_GENERAL_DISCLAIMER,
182     })
183     @Retention(RetentionPolicy.SOURCE)
184     public @interface Flags {
185         int SKIP_GENERAL_DISCLAIMER = 1;
186     }
187 }