• 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 
21 import static java.util.Objects.requireNonNull;
22 
23 import android.annotation.IntDef;
24 import android.content.Context;
25 import android.content.pm.ApplicationInfo;
26 import android.content.pm.PackageManager;
27 import android.content.res.Resources;
28 
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 
36 import java.io.File;
37 import java.io.IOException;
38 import java.lang.annotation.Retention;
39 import java.lang.annotation.RetentionPolicy;
40 import java.util.ArrayList;
41 import java.util.List;
42 import java.util.Objects;
43 import java.util.stream.Collectors;
44 
45 /**
46  * Sources all available {@link TermsDocument}s:
47  * <ul>
48  * <li> hardcoded 'General' terms,
49  * <li> terms exposed via installed apps,
50  * <li> terms passed from DPC.
51  * </ul>
52  */
53 public class TermsProvider {
54     private final Context mContext;
55     private final StoreUtils.TextFileReader mTextFileReader;
56     private final ProvisioningParams mParams;
57     private final Utils mUtils;
58     private final Injector mInjector;
59 
60     /**
61      * Sources all available {@link TermsDocument}s:
62      * <ul>
63      * <li> hardcoded 'General' terms,
64      * <li> terms exposed via installed apps,
65      * <li> terms passed from DPC.
66      * </ul>
67      */
TermsProvider(Context context, StoreUtils.TextFileReader textFileReader, ProvisioningParams params, Utils utils, Injector injector)68     public TermsProvider(Context context, StoreUtils.TextFileReader textFileReader,
69             ProvisioningParams params, Utils utils, Injector injector) {
70         mContext = requireNonNull(context);
71         mTextFileReader = requireNonNull(textFileReader);
72         mParams = requireNonNull(params);
73         mUtils = requireNonNull(utils);
74         mInjector = requireNonNull(injector);
75     }
76 
77     /**
78      * Sources all available {@link TermsDocument}s:
79      * <ul>
80      * <li> hardcoded 'General' terms,
81      * <li> terms exposed via installed apps,
82      * <li> terms passed from DPC.
83      * </ul>
84      */
getTerms()85     public List<TermsDocument> getTerms() {
86         List<TermsDocument> result = new ArrayList<>();
87         int provisioningCase = determineProvisioningCase(mParams);
88 
89         if (provisioningCase == ProvisioningCase.DEVICE_OWNER) {
90             result.addAll(getSystemAppTerms());
91         }
92 
93         result.addAll(getExtraDisclaimers(mParams));
94 
95         return result.stream().filter(Objects::nonNull).collect(Collectors.toList());
96     }
97 
98     /**
99      * Returns a generic disclaimer relative to the provisioning mode.
100      */
getGeneralDisclaimer()101     public TermsDocument getGeneralDisclaimer() {
102         int provisioningCase = determineProvisioningCase(mParams);
103         String heading = mContext.getString(provisioningCase == ProvisioningCase.PROFILE_OWNER
104                 ? R.string.work_profile_info
105                 : R.string.managed_device_info);
106         String content = mContext.getString(provisioningCase == ProvisioningCase.PROFILE_OWNER
107                 ? R.string.admin_has_ability_to_monitor_profile
108                 : R.string.admin_has_ability_to_monitor_device);
109         return TermsDocument.createInstance(heading, content);
110     }
111 
determineProvisioningCase(ProvisioningParams params)112     private int determineProvisioningCase(ProvisioningParams params) {
113         if (mUtils.isDeviceOwnerAction(params.provisioningAction)) {
114             return ProvisioningCase.DEVICE_OWNER;
115         }
116         return ProvisioningCase.PROFILE_OWNER;
117     }
118 
getSystemAppTerms()119     private List<TermsDocument> getSystemAppTerms() {
120         List<TermsDocument> terms = new ArrayList<>();
121         List<ApplicationInfo> appInfos = mInjector.getInstalledApplications();
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     })
172     @Retention(RetentionPolicy.SOURCE)
173     private @interface ProvisioningCase {
174         int PROFILE_OWNER = 1;
175         int DEVICE_OWNER = 2;
176     }
177 
178     interface Injector {
getInstalledApplications()179         List<ApplicationInfo> getInstalledApplications();
180     }
181 }