Skip to content
This repository has been archived by the owner on Feb 20, 2023. It is now read-only.

For #162 - remove dependency to play-services-oss-licenses library #13767

Merged
merged 1 commit into from
Aug 18, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,6 @@ dependencies {
implementation Deps.androidx_coordinatorlayout

implementation Deps.sentry
implementation Deps.osslicenses_library

implementation Deps.leanplum_core
implementation Deps.leanplum_fcm
Expand Down
9 changes: 2 additions & 7 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -228,13 +228,8 @@
<activity android:name=".settings.account.AuthIntentReceiverActivity"
android:exported="false" />

<activity android:name="com.google.android.gms.oss.licenses.OssLicensesMenuActivity"
android:exported="false"
android:theme="@style/Theme.AppCompat.DayNight.DarkActionBar"/>

<activity android:name="com.google.android.gms.oss.licenses.OssLicensesActivity"
android:exported="false"
android:theme="@style/Theme.AppCompat.DayNight.DarkActionBar"/>
<activity android:name=".settings.about.AboutLibrariesActivity"
android:exported="false" />

<service android:name=".media.MediaService"
android:exported="false" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import android.view.ViewGroup
import androidx.core.content.pm.PackageInfoCompat
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.DividerItemDecoration
import com.google.android.gms.oss.licenses.OssLicensesMenuActivity
import kotlinx.android.synthetic.main.fragment_about.*
import org.mozilla.fenix.BrowserDirection
import org.mozilla.fenix.BuildConfig
Expand Down Expand Up @@ -168,13 +167,8 @@ class AboutFragment : Fragment(), AboutPageListener {
}

private fun openLibrariesPage() {
startActivity(Intent(context, OssLicensesMenuActivity::class.java))
OssLicensesMenuActivity.setActivityTitle(
getString(
R.string.open_source_licenses_title,
appName
)
)
val intent = Intent(requireContext(), AboutLibrariesActivity::class.java)
startActivity(intent)
}

override fun onAboutItemClicked(item: AboutItem) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package org.mozilla.fenix.settings.about

import android.graphics.Typeface
import android.os.Bundle
import android.text.util.Linkify
import android.widget.ArrayAdapter
import android.widget.ListView
import android.widget.TextView
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import org.mozilla.fenix.R
import java.nio.charset.Charset
import java.util.Locale

/**
* Displays the licenses of all the libraries used by Fenix.
*
* This is a re-implementation of play-services-oss-licenses library.
* We can't use the official implementation in the OSS flavor of Fenix
* because it is proprietary and closed-source.
*
* There are popular FLOSS alternatives to Google's plugin and library
* such as AboutLibraries (https://github.com/mikepenz/AboutLibraries)
* but we considered the risk of introducing such third-party dependency
* to Fenix too high. Therefore, we use Google's gradle plugin to
* extract the dependencies and their licenses, and this activity
* to show the extracted licenses to the end-user.
*/
class AboutLibrariesActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

val appName = getString(R.string.app_name)
title = getString(R.string.open_source_licenses_title, appName)
setContentView(R.layout.about_libraries_activity)

setSupportActionBar(findViewById(R.id.toolbar))
supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.setDisplayShowHomeEnabled(true)

setupLibrariesListView()
}

override fun onSupportNavigateUp(): Boolean {
onBackPressed()
return true
}

private fun setupLibrariesListView() {
val libraries = parseLibraries()
val listView = findViewById<ListView>(R.id.about_libraries_listview)
listView.adapter = ArrayAdapter(this, android.R.layout.simple_list_item_1, libraries)
listView.setOnItemClickListener { _, _, position, _ ->
showLicenseDialog(libraries[position])
}
}

private fun parseLibraries(): List<LibraryItem> {
/*
The gradle plugin "oss-licenses-plugin" creates two "raw" resources:

- third_party_licenses which is the binary concatenation of all the licenses text for
all the libraries. License texts can either be an URL to a license file or just the
raw text of the license.

- third_party_licenses_metadata which contains one dependency per line formatted in
the following way: "[start_offset]:[length] [name]"

[start_offset] : first byte in third_party_licenses that contains the license
text for this library.
[length] : length of the license text for this library in
third_party_licenses.
[name] : either the name of the library, or its artifact name.

See https://github.com/google/play-services-plugins/tree/master/oss-licenses-plugin
*/
val licensesData = resources
.openRawResource(R.raw.third_party_licenses)
.readBytes()
val licensesMetadataReader = resources
.openRawResource(R.raw.third_party_license_metadata)
.bufferedReader()

return licensesMetadataReader.use { reader -> reader.readLines() }.map { line ->
val (section, name) = line.split(" ", limit = 2)
val (startOffset, length) = section.split(":", limit = 2).map(String::toInt)
val licenseData = licensesData.sliceArray(startOffset until startOffset + length)
val licenseText = licenseData.toString(Charset.forName("UTF-8"))
LibraryItem(name, licenseText)
}.sortedBy { item -> item.name.toLowerCase(Locale.ROOT) }
}

private fun showLicenseDialog(libraryItem: LibraryItem) {
val dialog = AlertDialog.Builder(this)
.setTitle(libraryItem.name)
.setMessage(libraryItem.license)
.create()
dialog.show()

val textView = dialog.findViewById<TextView>(android.R.id.message)!!
Linkify.addLinks(textView, Linkify.ALL)
textView.linksClickable = true
textView.textSize = LICENSE_TEXT_SIZE
textView.typeface = Typeface.MONOSPACE
}

companion object {
private const val LICENSE_TEXT_SIZE = 10F
}
}

private class LibraryItem(val name: String, val license: String) {
override fun toString(): String {
return name
}
}
25 changes: 25 additions & 0 deletions app/src/main/res/layout/about_libraries_activity.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->

<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/about_libraries"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
tools:context="org.mozilla.fenix.settings.about.AboutLibrariesActivity">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:elevation="4dp"
android:theme="@style/ThemeOverlay.AppCompat.ActionBar" />
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/about_libraries_listview" />
</RelativeLayout>
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package org.mozilla.fenix.settings.about

import android.widget.ListView
import android.widget.TextView
import org.junit.Assert.assertTrue
import org.junit.Test
import org.junit.runner.RunWith
import org.mozilla.fenix.R
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
import org.robolectric.Robolectric
import org.robolectric.Shadows.shadowOf
import org.robolectric.shadows.ShadowAlertDialog

@RunWith(FenixRobolectricTestRunner::class)
class AboutLibrariesActivityTest {
@Test
fun `activity should display licenses`() {
val activity = Robolectric.buildActivity(AboutLibrariesActivity::class.java).create().get()
val listView = activity.findViewById<ListView>(R.id.about_libraries_listview)

assertTrue(0 < listView.count)
}

@Test
fun `item click should open license dialog`() {
val activity = Robolectric.buildActivity(AboutLibrariesActivity::class.java).create().get()

val listView = activity.findViewById<ListView>(R.id.about_libraries_listview)
val listViewShadow = shadowOf(listView)
listViewShadow.clickFirstItemContainingText("org.mozilla.geckoview:geckoview")

val alertDialogShadow = ShadowAlertDialog.getLatestDialog()
assertTrue(alertDialogShadow.isShowing)

val alertDialogText = alertDialogShadow
.findViewById<TextView>(android.R.id.message)
.text
.toString()
assertTrue(alertDialogText.contains("MPL"))
}
}
2 changes: 0 additions & 2 deletions buildSrc/src/main/java/Dependencies.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ object Versions {
const val leakcanary = "2.4"
const val leanplum = "5.4.0"
const val osslicenses_plugin = "0.9.5"
const val osslicenses_library = "17.0.0"
const val detekt = "1.9.1"

const val androidx_appcompat = "1.2.0-rc01"
Expand Down Expand Up @@ -59,7 +58,6 @@ object Deps {

const val allopen = "org.jetbrains.kotlin:kotlin-allopen:${Versions.kotlin}"
const val osslicenses_plugin = "com.google.android.gms:oss-licenses-plugin:${Versions.osslicenses_plugin}"
const val osslicenses_library = "com.google.android.gms:play-services-oss-licenses:${Versions.osslicenses_library}"

const val mozilla_concept_engine = "org.mozilla.components:concept-engine:${Versions.mozilla_android_components}"
const val mozilla_concept_menu = "org.mozilla.components:concept-menu:${Versions.mozilla_android_components}"
Expand Down