1 /*
2  * Copyright 2016, 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.parser;
17 
18 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DISCLAIMERS;
19 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DISCLAIMER_CONTENT;
20 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DISCLAIMER_HEADER;
21 import static com.android.managedprovisioning.common.StoreUtils.DIR_PROVISIONING_PARAMS_FILE_CACHE;
22 
23 import android.content.Context;
24 import android.net.Uri;
25 import android.os.Bundle;
26 import android.os.Parcelable;
27 import androidx.annotation.Nullable;
28 import androidx.annotation.VisibleForTesting;
29 import android.text.TextUtils;
30 import com.android.managedprovisioning.common.ProvisionLogger;
31 import com.android.managedprovisioning.common.StoreUtils;
32 import com.android.managedprovisioning.model.DisclaimersParam;
33 import com.android.managedprovisioning.model.DisclaimersParam.Disclaimer;
34 import java.io.File;
35 import java.util.ArrayList;
36 import java.util.List;
37 
38 /**
39  * Parser for {@link EXTRA_PROVISIONING_DISCLAIMERS} into {@link DisclaimersParam}
40  * It also saves the disclaimer content into files
41  */
42 public class DisclaimersParser {
43     private static final int MAX_LENGTH = 3;
44 
45     private final Context mContext;
46     private final long mProvisioningId;
47     private final File mDisclaimerDir;
48 
DisclaimersParser(Context context, long provisioningId)49     public DisclaimersParser(Context context, long provisioningId) {
50         mContext = context;
51         mProvisioningId = provisioningId;
52         mDisclaimerDir =  new File(mContext.getFilesDir(), DIR_PROVISIONING_PARAMS_FILE_CACHE);
53     }
54 
55     @Nullable
parse(Parcelable[] parcelables)56     public DisclaimersParam parse(Parcelable[] parcelables) throws ClassCastException {
57         if (parcelables == null) {
58             return null;
59         }
60 
61         List<Disclaimer> disclaimers = new ArrayList<>(MAX_LENGTH);
62         for (int i = 0; i < parcelables.length; i++) {
63             // maximum 3 disclaimers are accepted in the EXTRA_PROVISIONING_DISCLAIMERS API
64             if (disclaimers.size() >= MAX_LENGTH) {
65                 break;
66             }
67             final Bundle disclaimerBundle = (Bundle) parcelables[i];
68             final String header = disclaimerBundle.getString(EXTRA_PROVISIONING_DISCLAIMER_HEADER);
69             final Uri uri = disclaimerBundle.getParcelable(EXTRA_PROVISIONING_DISCLAIMER_CONTENT);
70             if (TextUtils.isEmpty(header)) {
71                 ProvisionLogger.logw("Empty disclaimer header in " + i + " element");
72                 continue;
73             }
74 
75             if (uri == null) {
76                 ProvisionLogger.logw("Null disclaimer content uri in " + i + " element");
77                 continue;
78             }
79 
80             File disclaimerFile = saveDisclaimerContentIntoFile(uri, i);
81 
82             if (disclaimerFile == null) {
83                 ProvisionLogger.logw("Failed to copy disclaimer uri in " + i + " element");
84                 continue;
85             }
86 
87             disclaimers.add(new Disclaimer(header, disclaimerFile.getPath()));
88         }
89         return disclaimers.isEmpty() ? null : new DisclaimersParam.Builder()
90                 .setDisclaimers(disclaimers.toArray(new Disclaimer[disclaimers.size()])).build();
91     }
92 
93     /**
94      * @return {@link File} if the uri content is saved into the file successfully. Otherwise,
95      * return null.
96      */
saveDisclaimerContentIntoFile(Uri uri, int index)97     private File saveDisclaimerContentIntoFile(Uri uri, int index) {
98         if (!mDisclaimerDir.exists()) {
99             mDisclaimerDir.mkdirs();
100         }
101 
102         String filename = "disclaimer_content_" + mProvisioningId + "_" + index + ".txt";
103         File outputFile = new File(mDisclaimerDir, filename);
104 
105         boolean success = StoreUtils.copyUriIntoFile(mContext.getContentResolver(), uri,
106                 outputFile);
107         return success ? outputFile : null;
108     }
109 }
110