Licenses.java revision 633eb826b8c97731dfc5ef12c7bf78a63734275d
1/*
2 * Copyright (C) 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
17package com.android.tv.license;
18
19import android.content.Context;
20import android.support.annotation.RawRes;
21
22import com.android.tv.R;
23import com.android.tv.common.SoftPreconditions;
24
25import java.io.ByteArrayOutputStream;
26import java.io.IOException;
27import java.io.InputStream;
28import java.io.UnsupportedEncodingException;
29import java.util.ArrayList;
30import java.util.Collections;
31
32/**
33 * A helper for extracting licenses embedded using
34 * third_party_licenses.build:third_party_licenses().
35 */
36public final class Licenses {
37
38    public static final String TAG = "Licenses";
39    public static boolean hasLicenses(Context context) {
40        return !getTextFromResource(
41                        context.getApplicationContext(), R.raw.third_party_license_metadata, 0, -1)
42                .isEmpty();
43    }
44
45    /** Return the licenses bundled into this app. */
46    public static ArrayList<License> getLicenses(Context context) {
47        return getLicenseListFromMetadata(
48                getTextFromResource(
49                        context.getApplicationContext(), R.raw.third_party_license_metadata, 0, -1),
50                "");
51    }
52
53    /**
54     * Returns a list of {@link License}s parsed from a license metadata file.
55     *
56     * @param metadata a {@code String} containing the contents of a license metadata file.
57     * @param filePath a path to a package archive with licenses or empty string for the app package
58     */
59    private static ArrayList<License> getLicenseListFromMetadata(String metadata, String filePath) {
60        String[] entries = metadata.split("\n");
61        ArrayList<License> licenses = new ArrayList<License>(entries.length);
62        for (String entry : entries) {
63            int delimiter = entry.indexOf(' ');
64            String[] licenseLocation = entry.substring(0, delimiter).split(":");
65            SoftPreconditions.checkState(
66                    licenseLocation.length == 2 && delimiter > 0,
67                    TAG,
68                    "Invalid license meta-data line:\n" + entry);
69            long licenseOffset = Long.parseLong(licenseLocation[0]);
70            int licenseLength = Integer.parseInt(licenseLocation[1]);
71            licenses.add(
72                    License.create(
73                            entry.substring(delimiter + 1),
74                            licenseOffset,
75                            licenseLength,
76                            filePath));
77        }
78        Collections.sort(licenses);
79        return licenses;
80    }
81
82    /** Return the text of a bundled license file. */
83    public static String getLicenseText(Context context, License license) {
84        long offset = license.getLicenseOffset();
85        int length = license.getLicenseLength();
86        return getTextFromResource(context, R.raw.third_party_licenses, offset, length);
87    }
88
89    private static String getTextFromResource(
90            Context context, @RawRes int resourcesIdentifier, long offset, int length) {
91        InputStream stream =
92                context.getApplicationContext().getResources().openRawResource(resourcesIdentifier);
93        return getTextFromInputStream(stream, offset, length);
94    }
95
96    private static String getTextFromInputStream(InputStream stream, long offset, int length) {
97        byte[] buffer = new byte[1024];
98        ByteArrayOutputStream textArray = new ByteArrayOutputStream();
99
100        try {
101            stream.skip(offset);
102            int bytesRemaining = length > 0 ? length : Integer.MAX_VALUE;
103            int bytes = 0;
104
105            while (bytesRemaining > 0
106                    && (bytes = stream.read(buffer, 0, Math.min(bytesRemaining, buffer.length)))
107                            != -1) {
108                textArray.write(buffer, 0, bytes);
109                bytesRemaining -= bytes;
110            }
111            stream.close();
112        } catch (IOException e) {
113            throw new RuntimeException("Failed to read license or metadata text.", e);
114        }
115        try {
116            return textArray.toString("UTF-8");
117        } catch (UnsupportedEncodingException e) {
118            throw new RuntimeException(
119                    "Unsupported encoding UTF8. This should always be supported.", e);
120        }
121    }
122}
123