diff --git a/app/src/main/java/org/mozilla/fenix/settings/AboutPage.kt b/app/src/main/java/org/mozilla/fenix/settings/AboutPage.kt index 6005e40cc..ebcde6e34 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/AboutPage.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/AboutPage.kt @@ -9,10 +9,12 @@ package org.mozilla.fenix.settings import android.content.Context import android.content.pm.PackageManager import androidx.annotation.RawRes -import org.mozilla.fenix.R 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 { @@ -36,9 +38,12 @@ object AboutPage { substitutionMap["%build-date%"] = BUILD_DATE - context.resources.getString(R.string.about_content, appName).also { content -> - substitutionMap["%about-content%"] = content - } + 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) } diff --git a/app/src/main/java/org/mozilla/fenix/settings/SettingsFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/SettingsFragment.kt index ef0987bc1..d1f66d56d 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/SettingsFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/SettingsFragment.kt @@ -5,6 +5,8 @@ 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 import android.widget.Toast @@ -13,19 +15,31 @@ import androidx.navigation.Navigation import androidx.preference.Preference import androidx.preference.Preference.OnPreferenceClickListener 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.support.ktx.android.graphics.toDataUri import org.mozilla.fenix.BuildConfig import org.mozilla.fenix.FenixApplication import org.mozilla.fenix.R -import org.mozilla.fenix.R.string.pref_key_about import org.mozilla.fenix.R.string.pref_key_leakcanary import org.mozilla.fenix.R.string.pref_key_make_default_browser import org.mozilla.fenix.ext.getPreferenceKey import org.mozilla.fenix.ext.requireComponents +import java.io.File +import kotlin.coroutines.CoroutineContext -class SettingsFragment : PreferenceFragmentCompat() { +class SettingsFragment : PreferenceFragmentCompat(), CoroutineScope { + + private lateinit var job: Job + override val coroutineContext: CoroutineContext + get() = Dispatchers.Main + job override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + job = Job() (activity as AppCompatActivity).supportActionBar?.show() } @@ -36,21 +50,70 @@ class SettingsFragment : PreferenceFragmentCompat() { override fun onResume() { super.onResume() + generateWordmark() setupPreferences() } + override fun onPreferenceTreeClick(preference: Preference): Boolean { + when (preference.key) { + resources.getString(R.string.pref_key_help) -> { + requireComponents.useCases.tabsUseCases.addTab + .invoke(SupportUtils.getSumoURLForTopic(context!!, SupportUtils.SumoTopic.HELP)) + navigateToSettingsArticle() + } + resources.getString(R.string.pref_key_rate) -> { + startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(SupportUtils.RATE_APP_URL))) + } + resources.getString(R.string.pref_key_feedback) -> { + requireComponents.useCases.tabsUseCases.addTab.invoke(SupportUtils.FEEDBACK_URL) + navigateToSettingsArticle() + } + resources.getString(R.string.pref_key_about) -> { + requireComponents.useCases.tabsUseCases.addTab.invoke(aboutURL, true) + navigateToSettingsArticle() + } + } + return super.onPreferenceTreeClick(preference) + } + + override fun onDestroy() { + super.onDestroy() + job.cancel() + } + + /** + * 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 aboutKey = context?.getPreferenceKey(pref_key_about) val leakKey = context?.getPreferenceKey(pref_key_leakcanary) val preferenceMakeDefaultBrowser = findPreference(makeDefaultBrowserKey) - val preferenceAbout = findPreference(aboutKey) val preferenceLeakCanary = findPreference(leakKey) preferenceMakeDefaultBrowser.onPreferenceClickListener = getClickListenerForMakeDefaultBrowser() - preferenceAbout.onPreferenceClickListener = getAboutPageListener() preferenceLeakCanary.isVisible = BuildConfig.DEBUG if (BuildConfig.DEBUG) { @@ -81,18 +144,17 @@ class SettingsFragment : PreferenceFragmentCompat() { } } - private fun getAboutPageListener(): OnPreferenceClickListener { - return OnPreferenceClickListener { - requireComponents.useCases.tabsUseCases.addTab.invoke(aboutURL, true) - view?.let { - Navigation.findNavController(it) - .navigate(SettingsFragmentDirections.actionGlobalBrowser(null)) - } - true + private fun navigateToSettingsArticle() { + requireComponents.useCases.tabsUseCases.addTab.invoke(aboutURL, true) + view?.let { + Navigation.findNavController(it) + .navigate(SettingsFragmentDirections.actionGlobalBrowser(null)) } } companion object { + const val wordmarkScalingFactor = 2 + const val wordmarkPath = "wordmark.b64" const val aboutURL = "about:version" } } diff --git a/app/src/main/java/org/mozilla/fenix/settings/SupportUtils.kt b/app/src/main/java/org/mozilla/fenix/settings/SupportUtils.kt new file mode 100644 index 000000000..f1632d9e5 --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/settings/SupportUtils.kt @@ -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.Context +import android.content.pm.PackageManager +import org.mozilla.fenix.BuildConfig +import java.io.UnsupportedEncodingException +import java.net.URLEncoder +import java.util.Locale + +object SupportUtils { + const val FEEDBACK_URL = "https://input.mozilla.org" + const val RATE_APP_URL = "market://details?id=" + BuildConfig.APPLICATION_ID + const val MOZILLA_MANIFESTO_URL = "https://www.mozilla.org/en-GB/about/manifesto/" + + enum class SumoTopic( + internal val topicStr: String + ) { + HELP("firefox-android-help") + } + + fun getSumoURLForTopic(context: Context, topic: SumoTopic): String { + val escapedTopic = getEncodedTopicUTF8(topic.topicStr) + val appVersion = getAppVersion(context) + val osTarget = "Android" + val langTag = Locale.getDefault().isO3Language + return "https://support.mozilla.org/1/mobile/$appVersion/$osTarget/$langTag/$escapedTopic" + } + + private fun getEncodedTopicUTF8(topic: String): String { + try { + return URLEncoder.encode(topic, "UTF-8") + } catch (e: UnsupportedEncodingException) { + throw IllegalStateException("utf-8 should always be available", e) + } + } + + private fun getAppVersion(context: Context): String { + try { + return context.packageManager.getPackageInfo(context.packageName, 0).versionName + } catch (e: PackageManager.NameNotFoundException) { + // This should be impossible - we should always be able to get information about ourselves: + throw IllegalStateException("Unable find package details for Fenix", e) + } + } +} diff --git a/app/src/main/res/raw/about.html b/app/src/main/res/raw/about.html index fc7bb5f77..248ea30b7 100644 --- a/app/src/main/res/raw/about.html +++ b/app/src/main/res/raw/about.html @@ -4,48 +4,50 @@ - You can obtain one at http://mozilla.org/MPL/2.0/. --> + name="viewport" + charset="utf-8" + content="width=device-width, initial-scale=1"> -

Fenix

+ class="about"> +
+ +

%about-version%

%about-content% -

Built on: %build-date%

- + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e60c61268..5a59b7e28 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -131,10 +131,10 @@ History item menu - %1$s puts you in control.

-

%1$s is produced by Mozilla. Our mission is to foster a healthy, open Internet.
+

%1$s is made by Mozilla: a global community that makes browsers, apps, code and tools that put +people before profit. Our mission: keep the Internet open and accessible to all.
+Learn more

]]>