aboutsummaryrefslogtreecommitdiff
path: root/src/com/android/tv/license
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/tv/license')
-rw-r--r--src/com/android/tv/license/License.java112
-rw-r--r--src/com/android/tv/license/LicenseDialogFragment.java97
-rw-r--r--src/com/android/tv/license/LicenseSideFragment.java80
-rw-r--r--src/com/android/tv/license/LicenseUtils.java12
-rw-r--r--src/com/android/tv/license/Licenses.java122
5 files changed, 411 insertions, 12 deletions
diff --git a/src/com/android/tv/license/License.java b/src/com/android/tv/license/License.java
new file mode 100644
index 00000000..c1cbd09e
--- /dev/null
+++ b/src/com/android/tv/license/License.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.tv.license;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Container class to store the name of a library and the filename of its associated license file.
+ */
+public final class License implements Comparable<License>, Parcelable {
+ // Name of the third-party library.
+ private final String mLibraryName;
+ // Byte offset in the file to the start of the license text.
+ private final long mLicenseOffset;
+ // Byte length of the license text.
+ private final int mLicenseLength;
+ // Path to the archive that has bundled licenses.
+ // Empty string if the license is bundled in the apk itself.
+ private final String mPath;
+
+ /**
+ * Create an object representing a stored license. The text for all licenses is stored in a
+ * single file, so the offset and length describe this license's position within the file.
+ *
+ * @param path a path to an .apk-compatible archive that contains the license. An empty string
+ * in case the license is contained within the app itself.
+ */
+ static License create(String libraryName, long licenseOffset, int licenseLength, String path) {
+ return new License(libraryName, licenseOffset, licenseLength, path);
+ }
+
+ public static final Parcelable.Creator<License> CREATOR =
+ new Parcelable.Creator<License>() {
+ @Override
+ public License createFromParcel(Parcel in) {
+ return new License(in);
+ }
+
+ @Override
+ public License[] newArray(int size) {
+ return new License[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mLibraryName);
+ dest.writeLong(mLicenseOffset);
+ dest.writeInt(mLicenseLength);
+ dest.writeString(mPath);
+ }
+
+ @Override
+ public int compareTo(License o) {
+ return mLibraryName.compareToIgnoreCase(o.getLibraryName());
+ }
+
+ @Override
+ public String toString() {
+ return getLibraryName();
+ }
+
+ private License(String libraryName, long licenseOffset, int licenseLength, String path) {
+ this.mLibraryName = libraryName;
+ this.mLicenseOffset = licenseOffset;
+ this.mLicenseLength = licenseLength;
+ this.mPath = path;
+ }
+
+ private License(Parcel in) {
+ mLibraryName = in.readString();
+ mLicenseOffset = in.readLong();
+ mLicenseLength = in.readInt();
+ mPath = in.readString();
+ }
+
+ String getLibraryName() {
+ return mLibraryName;
+ }
+
+ long getLicenseOffset() {
+ return mLicenseOffset;
+ }
+
+ int getLicenseLength() {
+ return mLicenseLength;
+ }
+
+ public String getPath() {
+ return mPath;
+ }
+}
diff --git a/src/com/android/tv/license/LicenseDialogFragment.java b/src/com/android/tv/license/LicenseDialogFragment.java
new file mode 100644
index 00000000..b0e09776
--- /dev/null
+++ b/src/com/android/tv/license/LicenseDialogFragment.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.tv.license;
+
+import android.app.DialogFragment;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.text.TextUtils;
+import android.text.method.ScrollingMovementMethod;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
+import android.widget.TextView;
+
+import com.android.tv.R;
+import com.android.tv.dialog.SafeDismissDialogFragment;
+
+/** A DialogFragment that shows a License in a text view. */
+public class LicenseDialogFragment extends SafeDismissDialogFragment {
+ public static final String DIALOG_TAG = LicenseDialogFragment.class.getSimpleName();
+
+ private static final String LICENSE = "LICENSE";
+
+ private License mLicense;
+ private String mTrackerLabel;
+
+ /**
+ * Create a new LicenseDialogFragment to show a particular license.
+ *
+ * @param license The License to show.
+ */
+ public static LicenseDialogFragment newInstance(License license) {
+ LicenseDialogFragment f = new LicenseDialogFragment();
+ Bundle args = new Bundle();
+ args.putParcelable(LICENSE, license);
+ f.setArguments(args);
+ return f;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mLicense = getArguments().getParcelable(LICENSE);
+ String title = mLicense.getLibraryName();
+ mTrackerLabel = getArguments().getString(title + "_license");
+ int style =
+ TextUtils.isEmpty(title)
+ ? DialogFragment.STYLE_NO_TITLE
+ : DialogFragment.STYLE_NORMAL;
+ setStyle(style, 0);
+ }
+
+ @Nullable
+ @Override
+ public View onCreateView(
+ LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ TextView textView = new TextView(getActivity());
+ String licenseText = Licenses.getLicenseText(getContext(), mLicense);
+ textView.setText(licenseText != null ? licenseText : "");
+ textView.setMovementMethod(new ScrollingMovementMethod());
+ int verticalOverscan =
+ getResources().getDimensionPixelSize(R.dimen.vertical_overscan_safe_margin);
+ int horizontalOverscan =
+ getResources().getDimensionPixelSize(R.dimen.horizontal_overscan_safe_margin);
+ textView.setPadding(
+ horizontalOverscan, verticalOverscan, horizontalOverscan, verticalOverscan);
+ return textView;
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ // Ensure the dialog is fullscreen, even if the TextView doesn't have its content yet.
+ getDialog().getWindow().setLayout(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+ getDialog().setTitle(mLicense.getLibraryName());
+ }
+
+ @Override
+ public String getTrackerLabel() {
+ return mTrackerLabel;
+ }
+}
diff --git a/src/com/android/tv/license/LicenseSideFragment.java b/src/com/android/tv/license/LicenseSideFragment.java
new file mode 100644
index 00000000..fd92467c
--- /dev/null
+++ b/src/com/android/tv/license/LicenseSideFragment.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.tv.license;
+
+import android.content.Context;
+
+import com.android.tv.R;
+import com.android.tv.ui.sidepanel.ActionItem;
+import com.android.tv.ui.sidepanel.SideFragment;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** Opens a dialog showing open source licenses. */
+public final class LicenseSideFragment extends SideFragment {
+
+ public static final String TRACKER_LABEL = "Open Source Licenses";
+
+ public class LicenseActionItem extends ActionItem {
+ private final License license;
+
+ public LicenseActionItem(License license) {
+ super(license.getLibraryName());
+ this.license = license;
+ }
+
+ @Override
+ protected void onSelected() {
+ LicenseDialogFragment dialog = LicenseDialogFragment.newInstance(license);
+ getMainActivity()
+ .getOverlayManager()
+ .showDialogFragment(LicenseDialogFragment.DIALOG_TAG, dialog, true);
+ }
+ }
+
+ private List<LicenseActionItem> licenses;
+
+ @Override
+ public void onAttach(Context context) {
+ super.onAttach(context);
+ licenses = toActionItems(Licenses.getLicenses(context));
+ }
+
+ private List<LicenseActionItem> toActionItems(ArrayList<License> licenses) {
+ List<LicenseActionItem> items = new ArrayList<>(licenses.size());
+ for (License license : licenses) {
+ items.add(new LicenseActionItem(license));
+ }
+ return items;
+ }
+
+ @Override
+ protected String getTitle() {
+ return getResources().getString(R.string.settings_menu_licenses);
+ }
+
+ @Override
+ public String getTrackerLabel() {
+ return TRACKER_LABEL;
+ }
+
+ @Override
+ protected List<LicenseActionItem> getItemList() {
+ return licenses;
+ }
+}
diff --git a/src/com/android/tv/license/LicenseUtils.java b/src/com/android/tv/license/LicenseUtils.java
index b972aad6..cf3fe751 100644
--- a/src/com/android/tv/license/LicenseUtils.java
+++ b/src/com/android/tv/license/LicenseUtils.java
@@ -26,21 +26,9 @@ import java.io.InputStream;
* Utilities for showing open source licenses.
*/
public final class LicenseUtils {
- public final static String LICENSE_FILE = "file:///android_asset/licenses.html";
public final static String RATING_SOURCE_FILE =
"file:///android_asset/rating_sources.html";
- private final static File licenseFile = new File(LICENSE_FILE);
- /**
- * Checks if the license.html asset is include in the apk.
- */
- public static boolean hasLicenses(AssetManager am) {
- try (InputStream is = am.open("licenses.html")) {
- return true;
- } catch (IOException e) {
- return false;
- }
- }
/**
* Checks if the rating_attribution.html asset is include in the apk.
diff --git a/src/com/android/tv/license/Licenses.java b/src/com/android/tv/license/Licenses.java
new file mode 100644
index 00000000..4b8a7ffc
--- /dev/null
+++ b/src/com/android/tv/license/Licenses.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.tv.license;
+
+import android.content.Context;
+import android.support.annotation.RawRes;
+
+import com.android.tv.R;
+import com.android.tv.common.SoftPreconditions;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.Collections;
+
+/**
+ * A helper for extracting licenses embedded using
+ * third_party_licenses.build:third_party_licenses().
+ */
+public final class Licenses {
+
+ public static final String TAG = "Licenses";
+ public static boolean hasLicenses(Context context) {
+ return !getTextFromResource(
+ context.getApplicationContext(), R.raw.third_party_license_metadata, 0, -1)
+ .isEmpty();
+ }
+
+ /** Return the licenses bundled into this app. */
+ public static ArrayList<License> getLicenses(Context context) {
+ return getLicenseListFromMetadata(
+ getTextFromResource(
+ context.getApplicationContext(), R.raw.third_party_license_metadata, 0, -1),
+ "");
+ }
+
+ /**
+ * Returns a list of {@link License}s parsed from a license metadata file.
+ *
+ * @param metadata a {@code String} containing the contents of a license metadata file.
+ * @param filePath a path to a package archive with licenses or empty string for the app package
+ */
+ private static ArrayList<License> getLicenseListFromMetadata(String metadata, String filePath) {
+ String[] entries = metadata.split("\n");
+ ArrayList<License> licenses = new ArrayList<License>(entries.length);
+ for (String entry : entries) {
+ int delimiter = entry.indexOf(' ');
+ String[] licenseLocation = entry.substring(0, delimiter).split(":");
+ SoftPreconditions.checkState(
+ licenseLocation.length == 2 && delimiter > 0,
+ TAG,
+ "Invalid license meta-data line:\n" + entry);
+ long licenseOffset = Long.parseLong(licenseLocation[0]);
+ int licenseLength = Integer.parseInt(licenseLocation[1]);
+ licenses.add(
+ License.create(
+ entry.substring(delimiter + 1),
+ licenseOffset,
+ licenseLength,
+ filePath));
+ }
+ Collections.sort(licenses);
+ return licenses;
+ }
+
+ /** Return the text of a bundled license file. */
+ public static String getLicenseText(Context context, License license) {
+ long offset = license.getLicenseOffset();
+ int length = license.getLicenseLength();
+ return getTextFromResource(context, R.raw.third_party_licenses, offset, length);
+ }
+
+ private static String getTextFromResource(
+ Context context, @RawRes int resourcesIdentifier, long offset, int length) {
+ InputStream stream =
+ context.getApplicationContext().getResources().openRawResource(resourcesIdentifier);
+ return getTextFromInputStream(stream, offset, length);
+ }
+
+ private static String getTextFromInputStream(InputStream stream, long offset, int length) {
+ byte[] buffer = new byte[1024];
+ ByteArrayOutputStream textArray = new ByteArrayOutputStream();
+
+ try {
+ stream.skip(offset);
+ int bytesRemaining = length > 0 ? length : Integer.MAX_VALUE;
+ int bytes = 0;
+
+ while (bytesRemaining > 0
+ && (bytes = stream.read(buffer, 0, Math.min(bytesRemaining, buffer.length)))
+ != -1) {
+ textArray.write(buffer, 0, bytes);
+ bytesRemaining -= bytes;
+ }
+ stream.close();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to read license or metadata text.", e);
+ }
+ try {
+ return textArray.toString("UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(
+ "Unsupported encoding UTF8. This should always be supported.", e);
+ }
+ }
+}