Home | History | Annotate | Download | only in about
      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 
     17 package com.android.dialer.about;
     18 
     19 import android.content.Context;
     20 import android.content.res.Resources;
     21 import com.android.dialer.common.Assert;
     22 import java.io.ByteArrayOutputStream;
     23 import java.io.IOException;
     24 import java.io.InputStream;
     25 import java.io.UnsupportedEncodingException;
     26 import java.util.ArrayList;
     27 import java.util.Collections;
     28 
     29 /** A helper for extracting licenses. */
     30 public final class Licenses {
     31   private static final String TAG = "Licenses";
     32   private static final String LICENSE_FILENAME = "third_party_licenses";
     33   private static final String LICENSE_METADATA_FILENAME = "third_party_license_metadata";
     34 
     35   /** Return the licenses bundled into this app. */
     36   public static ArrayList<License> getLicenses(Context context) {
     37     return getLicenseListFromMetadata(
     38         getTextFromResource(context.getApplicationContext(), LICENSE_METADATA_FILENAME, 0, -1));
     39   }
     40 
     41   /**
     42    * Returns a list of {@link License}s parsed from a license metadata file.
     43    *
     44    * @param metadata a {@code String} containing the contents of a license metadata file.
     45    */
     46   private static ArrayList<License> getLicenseListFromMetadata(String metadata) {
     47     String[] entries = metadata.split("\n");
     48     ArrayList<License> licenses = new ArrayList<License>(entries.length);
     49     for (String entry : entries) {
     50       int delimiter = entry.indexOf(' ');
     51       String[] licenseLocation = entry.substring(0, delimiter).split(":");
     52       Assert.checkState(
     53           delimiter > 0 && licenseLocation.length == 2,
     54           "Invalid license meta-data line:\n" + entry);
     55       long licenseOffset = Long.parseLong(licenseLocation[0]);
     56       int licenseLength = Integer.parseInt(licenseLocation[1]);
     57       licenses.add(License.create(entry.substring(delimiter + 1), licenseOffset, licenseLength));
     58     }
     59     Collections.sort(licenses);
     60     return licenses;
     61   }
     62 
     63   /** Return the text of a bundled license file. */
     64   public static String getLicenseText(Context context, License license) {
     65     long offset = license.getLicenseOffset();
     66     int length = license.getLicenseLength();
     67     return getTextFromResource(context, LICENSE_FILENAME, offset, length);
     68   }
     69 
     70   private static String getTextFromResource(
     71       Context context, String filename, long offset, int length) {
     72     Resources resources = context.getApplicationContext().getResources();
     73     // When aapt is called with --rename-manifest-package, the package name is changed for the
     74     // application, but not for the resources. This is to find the package name of a known
     75     // resource to know what package to lookup the license files in.
     76     String packageName = resources.getResourcePackageName(R.id.dummy_placeholder);
     77     InputStream stream =
     78         resources.openRawResource(resources.getIdentifier(filename, "raw", packageName));
     79     return getTextFromInputStream(stream, offset, length);
     80   }
     81 
     82   private static String getTextFromInputStream(InputStream stream, long offset, int length) {
     83     byte[] buffer = new byte[1024];
     84     ByteArrayOutputStream textArray = new ByteArrayOutputStream();
     85 
     86     try {
     87       stream.skip(offset);
     88       int bytesRemaining = length > 0 ? length : Integer.MAX_VALUE;
     89       int bytes = 0;
     90 
     91       while (bytesRemaining > 0
     92           && (bytes = stream.read(buffer, 0, Math.min(bytesRemaining, buffer.length))) != -1) {
     93         textArray.write(buffer, 0, bytes);
     94         bytesRemaining -= bytes;
     95       }
     96       stream.close();
     97     } catch (IOException e) {
     98       throw new RuntimeException("Failed to read license or metadata text.", e);
     99     }
    100     try {
    101       return textArray.toString("UTF-8");
    102     } catch (UnsupportedEncodingException e) {
    103       throw new RuntimeException("Unsupported encoding UTF8. This should always be supported.", e);
    104     }
    105   }
    106 }
    107