Home | History | Annotate | Download | only in terms
      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      */
     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      */
     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 
     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 
    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 
    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 
    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 
    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 }