1
0
Fork 0

Fixes #1162 - replaces about page with an Android Fragment

master
Jeff Boek 2019-03-26 19:54:28 -07:00
parent 5f5bb47706
commit 379875a62a
9 changed files with 147 additions and 183 deletions

View File

@ -111,7 +111,7 @@ android.applicationVariants.all { variant ->
// Set up kotlin-allopen plugin for writing tests
// -------------------------------------------------------------------------------------------------
boolean hasTest = gradle.startParameter.taskNames.find {it.contains("test") || it.contains("Test")} != null
boolean hasTest = gradle.startParameter.taskNames.find { it.contains("test") || it.contains("Test") } != null
if (hasTest) {
apply plugin: 'kotlin-allopen'
allOpen {

View File

@ -9,25 +9,8 @@ import mozilla.components.browser.errorpages.ErrorPages
import mozilla.components.browser.errorpages.ErrorType
import mozilla.components.concept.engine.EngineSession
import mozilla.components.concept.engine.request.RequestInterceptor
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.settings.AboutPage
import org.mozilla.fenix.settings.SettingsFragment
class AppRequestInterceptor(private val context: Context) : RequestInterceptor {
override fun onLoadRequest(
session: EngineSession,
uri: String
): RequestInterceptor.InterceptionResponse? {
return when (uri) {
SettingsFragment.aboutURL -> {
val page = AboutPage.createAboutPage(context)
return RequestInterceptor.InterceptionResponse.Content(page, encoding = base64)
}
else -> context.components.services.accountsAuthFeature.interceptor.onLoadRequest(session, uri)
}
}
override fun onErrorRequest(
session: EngineSession,
errorType: ErrorType,
@ -35,8 +18,4 @@ class AppRequestInterceptor(private val context: Context) : RequestInterceptor {
): RequestInterceptor.ErrorResponse? {
return RequestInterceptor.ErrorResponse(ErrorPages.createErrorPage(context, errorType))
}
companion object {
const val base64 = "base64"
}
}

View File

@ -0,0 +1,49 @@
/* 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
import android.content.pm.PackageManager
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.fragment_about.*
import org.mozilla.fenix.R
import org.mozilla.geckoview.BuildConfig
class AboutFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_about, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val appName = requireContext().resources.getString(R.string.app_name)
(activity as AppCompatActivity).title = getString(R.string.preferences_about, appName)
val aboutText = try {
val packageInfo = requireContext().packageManager.getPackageInfo(requireContext().packageName, 0)
val geckoVersion = packageInfo.versionCode.toString() + " \uD83E\uDD8E " +
BuildConfig.MOZ_APP_VERSION + "-" + BuildConfig.MOZ_APP_BUILDID
String.format(
"%s (Build #%s)",
packageInfo.versionName,
geckoVersion
)
} catch (e: PackageManager.NameNotFoundException) {
""
}
val buildDate = org.mozilla.fenix.BuildConfig.BUILD_DATE
val content = resources.getString(R.string.about_content, appName)
about_text.text = aboutText
about_content.text = content
build_date.text = buildDate
}
}

View File

@ -1,61 +0,0 @@
/*
* 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
import android.content.Context
import android.content.pm.PackageManager
import androidx.annotation.RawRes
import org.mozilla.fenix.BuildConfig.BUILD_DATE
import org.mozilla.fenix.R
import org.mozilla.fenix.ext.replace
import org.mozilla.fenix.settings.SettingsFragment.Companion.wordmarkPath
import org.mozilla.geckoview.BuildConfig
import java.io.File
object AboutPage {
fun createAboutPage(context: Context): String {
val substitutionMap = mutableMapOf<String, String>()
val appName = context.resources.getString(R.string.app_name)
try {
val packageInfo = context.packageManager.getPackageInfo(context.packageName, 0)
val geckoVersion = packageInfo.versionCode.toString() + " \uD83E\uDD8E " +
BuildConfig.MOZ_APP_VERSION + "-" + BuildConfig.MOZ_APP_BUILDID
String.format(
"%s (Build #%s)",
packageInfo.versionName,
geckoVersion
).also { aboutVersion ->
substitutionMap["%about-version%"] = aboutVersion
}
} catch (e: PackageManager.NameNotFoundException) {
// Nothing to do if we can't find the package name.
}
substitutionMap["%build-date%"] = BUILD_DATE
context.resources.getString(R.string.about_content, appName, SupportUtils.MOZILLA_MANIFESTO_URL)
.also { content ->
substitutionMap["%about-content%"] = content
}
substitutionMap["%wordmark%"] = File(context.filesDir, wordmarkPath).readText()
return loadResourceFile(context, R.raw.about, substitutionMap)
}
private fun loadResourceFile(
context: Context,
@RawRes resId: Int,
replacements: Map<String, String>
): String {
context.resources.openRawResource(resId)
.bufferedReader()
.use { it.readText() }
.also { return it.replace(replacements) }
}
}

View File

@ -5,7 +5,6 @@
package org.mozilla.fenix.settings
import android.content.Intent
import android.graphics.BitmapFactory
import android.net.Uri
import android.os.Bundle
import android.provider.Settings
@ -18,16 +17,13 @@ import androidx.preference.PreferenceCategory
import androidx.preference.PreferenceFragmentCompat
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import mozilla.components.concept.sync.AccountObserver
import mozilla.components.concept.sync.OAuthAccount
import mozilla.components.concept.sync.Profile
import kotlin.coroutines.CoroutineContext
import java.io.File
import mozilla.components.service.fxa.FxaUnauthorizedException
import mozilla.components.support.ktx.android.graphics.toDataUri
import org.mozilla.fenix.BuildConfig
import org.mozilla.fenix.FenixApplication
import org.mozilla.fenix.HomeActivity
@ -85,7 +81,6 @@ class SettingsFragment : PreferenceFragmentCompat(), CoroutineScope, AccountObse
val appName = getString(R.string.app_name)
aboutPreference?.title = getString(R.string.preferences_about, appName)
generateWordmark()
setupPreferences()
setupAccountUI()
}
@ -122,8 +117,7 @@ class SettingsFragment : PreferenceFragmentCompat(), CoroutineScope, AccountObse
navigateToSettingsArticle()
}
resources.getString(pref_key_about) -> {
requireComponents.useCases.tabsUseCases.addTab.invoke(aboutURL, true)
navigateToSettingsArticle()
navigateToAbout()
}
resources.getString(pref_key_account) -> {
navigateToAccountSettings()
@ -164,30 +158,6 @@ class SettingsFragment : PreferenceFragmentCompat(), CoroutineScope, AccountObse
}
}
/**
* Shrinks the wordmark resolution on first run to ensure About Page loads quickly
*/
private fun generateWordmark() {
val path = context?.filesDir
val file = File(path, wordmarkPath)
path?.let {
if (!file.exists()) {
launch(IO) {
val options = BitmapFactory.Options().apply {
inSampleSize = wordmarkScalingFactor
inJustDecodeBounds = false
}
file.appendText(
BitmapFactory.decodeResource(
resources,
R.drawable.ic_logo_wordmark, options
).toDataUri()
)
}
}
}
}
private fun setupPreferences() {
val makeDefaultBrowserKey = context!!.getPreferenceKey(pref_key_make_default_browser)
val leakKey = context!!.getPreferenceKey(pref_key_leakcanary)
@ -263,6 +233,11 @@ class SettingsFragment : PreferenceFragmentCompat(), CoroutineScope, AccountObse
}
}
private fun navigateToAbout() {
val directions = SettingsFragmentDirections.actionSettingsFragmentToAboutFragment()
Navigation.findNavController(view!!).navigate(directions)
}
private fun navigateToAccountSettings() {
val directions =
SettingsFragmentDirections.actionSettingsFragmentToAccountSettingsFragment()
@ -319,10 +294,4 @@ class SettingsFragment : PreferenceFragmentCompat(), CoroutineScope, AccountObse
preferenceFirefoxAccount?.summary = profile.email.orEmpty()
}
}
companion object {
const val wordmarkScalingFactor = 2
const val wordmarkPath = "wordmark.b64"
const val aboutURL = "about:version"
}
}

View File

@ -0,0 +1,59 @@
<?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/. -->
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="org.mozilla.fenix.settings.AboutFragment">
<ImageView
android:id="@+id/wordmark"
android:importantForAccessibility="no"
android:src="?attr/fenixLogo"
android:layout_marginTop="24dp"
android:layout_height="wrap_content"
android:layout_width="0dp"
app:layout_constraintWidth_percent="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/about_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textSize="16sp"
android:layout_marginTop="24dp"
app:layout_constraintWidth_percent="0.8"
app:layout_constraintTop_toBottomOf="@id/wordmark"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:textAlignment="center" />
<TextView
android:id="@+id/about_content"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textSize="18sp"
android:layout_marginTop="16dp"
app:layout_constraintWidth_percent="0.8"
app:layout_constraintTop_toBottomOf="@id/about_text"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<TextView
android:id="@+id/build_date"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:textSize="16sp"
app:layout_constraintWidth_percent="0.8"
app:layout_constraintTop_toBottomOf="@id/about_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:textAlignment="center" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -106,6 +106,9 @@
<action
android:id="@+id/action_settingsFragment_to_searchEngineFragment"
app:destination="@id/searchEngineFragment" />
<action
android:id="@+id/action_settingsFragment_to_aboutFragment"
app:destination="@id/aboutFragment" />
</fragment>
<fragment android:id="@+id/dataChoicesFragment" android:name="org.mozilla.fenix.settings.DataChoicesFragment"
android:label="DataChoicesFragment"/>
@ -120,6 +123,11 @@
android:id="@+id/searchEngineFragment"
android:name="org.mozilla.fenix.settings.SearchEngineFragment"
android:label="SearchEngineFragment" />
<fragment
android:id="@+id/aboutFragment"
android:name="org.mozilla.fenix.settings.AboutFragment"
android:label="AboutFragment" />
<fragment android:id="@+id/crashReporterFragment" android:name="org.mozilla.fenix.crashes.CrashReporterFragment"
android:label="CrashReporterFragment">
<action

View File

@ -1,52 +0,0 @@
<!doctype html>
<!-- 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/. -->
<html>
<head>
<meta
name="viewport"
charset="utf-8"
content="width=device-width, initial-scale=1">
<style>
body, html {
background: #f9f9fa;
color: #0C0C0D;
font-family: sans-serif;
line-height: 24px;
font-size: 14px;
}
body{
padding-left: 24px;
padding-right: 24px;
margin-left: 0px;
margin-right: 0px;
}
a {
color: #0A9AF4;
}
p.subtitle {
text-align: center;
opacity: .7;
margin: 0;
}
img#wordmark {
/* We need to set the dp size here, because by default webview assumes the image is not
density specific (but since it's an android resource, we get a density specific version). */
width: 180px;
display: block;
margin-left: auto;
margin-right: auto;
padding-top: 24px;
}
</style>
</head>
<body class="about">
<br>
<img src="%wordmark%" id="wordmark"/>
<br>
<p class="subtitle">%about-version%</p>
%about-content%
<p class="subtitle">Built on: %build-date%</p>
</body>
</html>

View File

@ -14,7 +14,9 @@
<!-- Content description (not visible, for screen readers etc.): "Private Browsing" menu button. -->
<string name="content_description_disable_private_browsing_button">Disable private browsing</string>
<!-- Explanation for how sessions work -->
<string name="sessions_intro_description">Sessions help you return to the sites you visit often and those you\'ve just discovered. Start browsing and they\'ll begin to appear here. </string>
<string name="sessions_intro_description">Sessions help you return to the sites you visit often and those you\'ve
just discovered. Start browsing and they\'ll begin to appear here.
</string>
<!-- Placeholder text shown in the search bar before a user enters text -->
<string name="search_hint">Search or enter address</string>
@ -23,7 +25,11 @@
<string name="private_browsing_title">You\'re in a private session</string>
<!-- Explanation for private browsing displayed to users on home view when they first enable private mode
The first parameter is the name of the app defined in app_name (for example: Fenix) -->
<string name="private_browsing_explanation">%1$s clears your search and browsing history when you close your private session. While this doesn\'t make you anonymous to websites or your internet service provider, it makes it easier to keep what you do online private from anyone else who uses this device.\n\nCommon myths about private browsing</string>
<string name="private_browsing_explanation">%1$s clears your search and browsing history when you close your private
session. While this doesn\'t make you anonymous to websites or your internet service provider, it makes it
easier to keep what you do online private from anyone else who uses this device.\n\nCommon myths about private
browsing
</string>
<!-- Delete session button to erase your history in a private session -->
<string name="private_browsing_delete_session">Delete session</string>
@ -132,7 +138,9 @@
<!-- Preference for reducing image sizes, bandwidth and platform-level optimizations -->
<string name="preference_optimize">Optimize</string>
<!-- Label summary to explain how the optimize preference works -->
<string name="preference_optimize_summary">Lower image quality, throttle streaming bandwidth, and platform-level optimizations</string>
<string name="preference_optimize_summary">Lower image quality, throttle streaming bandwidth, and platform-level
optimizations
</string>
<!-- Preference for showing a list of websites that the default configurations won't apply to them -->
<string name="preference_exceptions">Exceptions</string>
<!-- Preference for applying recommend rules to all sites -->
@ -141,11 +149,15 @@
<string name="preference_recommended_settings_summary">
<b>Blocked</b>
\n Ads, autoplay sound and video (block playing media with sound), cookies (block third-party trackers cookies), trackers (allow some trackers), pop-up, website redirects. \n\n <b>Ask to allow</b>
\n Ads, autoplay sound and video (block playing media with sound), cookies (block third-party trackers cookies),
trackers (allow some trackers), pop-up, website redirects. \n\n
<b>Ask to allow</b>
\n Camera, location, microphone and notification. \n\n <b>Allowed</b>
\n Camera, location, microphone and notification. \n\n
<b>Allowed</b>
\n DRM audio and video, JavaScript, cache and site data, images.</string>
\n DRM audio and video, JavaScript, cache and site data, images.
</string>
<!-- Preference for applying custom rules to all sites -->
<string name="preference_custom_settings">Use custom settings</string>
<!-- Preference category for feature phone permissions likes Camera,Microphone, Location ... etc -->
@ -226,11 +238,12 @@
<string name="settings_title">Settings</string>
<!-- Content description (not visible, for screen readers etc.): "Menu icon for items on a history item" -->
<string name="content_description_history_menu">History item menu</string>
<!-- About content -->
<string name="about_content"><![CDATA[
<p>%1$s puts you in control.</p>
<p>%1$s is produced by Mozilla. Our mission is to foster a healthy, open Internet.<br/>
]]></string>
<!-- About content. Sentences are separated by two new lines -->
<string name="about_content">
%1$s puts you in control.
\n\n
%1$s is produced by Mozilla. Our mission is to foster a healthy, open Internet.
</string>
<!-- Sessions -->
<!-- Title for the list of tabs in the current session -->