From a64d8da15ff328dd2a8ad88faa4ef32c1b587402 Mon Sep 17 00:00:00 2001 From: Tiger Oakes Date: Tue, 13 Aug 2019 15:31:56 -0400 Subject: [PATCH] Closes #778 - Progressive Web Apps! --- app/src/main/AndroidManifest.xml | 6 +++ .../java/org/mozilla/fenix/FeatureFlags.kt | 5 +++ .../fenix/components/IntentProcessors.kt | 3 ++ .../org/mozilla/fenix/components/UseCases.kt | 5 ++- .../components/toolbar/DefaultToolbarMenu.kt | 2 +- .../customtabs/ExternalAppBrowserActivity.kt | 24 ++++++++--- .../customtabs/ExternalAppBrowserFragment.kt | 43 +++++++++++++++++-- app/src/main/res/navigation/nav_graph.xml | 6 +-- buildSrc/src/main/java/Dependencies.kt | 2 +- 9 files changed, 80 insertions(+), 16 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 4fb4c277a19a..4bdd7a7263e0 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -113,6 +113,12 @@ + + + + + + diff --git a/app/src/main/java/org/mozilla/fenix/FeatureFlags.kt b/app/src/main/java/org/mozilla/fenix/FeatureFlags.kt index 9de3f7a4512c..b4dc8a2d4055 100644 --- a/app/src/main/java/org/mozilla/fenix/FeatureFlags.kt +++ b/app/src/main/java/org/mozilla/fenix/FeatureFlags.kt @@ -55,4 +55,9 @@ object FeatureFlags { * Gives option in Settings to Delete Browsing Data on new menu option Quit */ val deleteDataOnQuit = nightly or debug + + /** + * Allows Progressive Web Apps to be installed to the device home screen. + */ + val progressiveWebApps = nightly or debug } diff --git a/app/src/main/java/org/mozilla/fenix/components/IntentProcessors.kt b/app/src/main/java/org/mozilla/fenix/components/IntentProcessors.kt index 514d74dc40b4..59e7c14c9bab 100644 --- a/app/src/main/java/org/mozilla/fenix/components/IntentProcessors.kt +++ b/app/src/main/java/org/mozilla/fenix/components/IntentProcessors.kt @@ -8,6 +8,8 @@ import android.content.Context import mozilla.components.browser.session.SessionManager import mozilla.components.feature.customtabs.CustomTabIntentProcessor import mozilla.components.feature.intent.processing.TabIntentProcessor +import mozilla.components.feature.pwa.ManifestStorage +import mozilla.components.feature.pwa.intent.WebAppIntentProcessor import mozilla.components.feature.search.SearchUseCases import mozilla.components.feature.session.SessionUseCases import org.mozilla.fenix.test.Mockable @@ -38,6 +40,7 @@ class IntentProcessors( val externalAppIntentProcessors by lazy { listOf( + WebAppIntentProcessor(sessionManager, sessionUseCases.loadUrl, ManifestStorage(context)), CustomTabIntentProcessor(sessionManager, sessionUseCases.loadUrl, context.resources) ) } diff --git a/app/src/main/java/org/mozilla/fenix/components/UseCases.kt b/app/src/main/java/org/mozilla/fenix/components/UseCases.kt index 850c9e907de9..2b6a6e591392 100644 --- a/app/src/main/java/org/mozilla/fenix/components/UseCases.kt +++ b/app/src/main/java/org/mozilla/fenix/components/UseCases.kt @@ -17,6 +17,7 @@ import mozilla.components.feature.search.SearchUseCases import mozilla.components.feature.session.SessionUseCases import mozilla.components.feature.session.SettingsUseCases import mozilla.components.feature.tabs.TabsUseCases +import org.mozilla.fenix.FeatureFlags.progressiveWebApps import org.mozilla.fenix.test.Mockable /** @@ -53,7 +54,9 @@ class UseCases( val appLinksUseCases by lazy { AppLinksUseCases(context.applicationContext) } - val webAppUseCases by lazy { WebAppUseCases(context, sessionManager, httpClient, supportWebApps = false) } + val webAppUseCases by lazy { + WebAppUseCases(context, sessionManager, httpClient, supportWebApps = progressiveWebApps) + } val downloadUseCases by lazy { DownloadsUseCases(sessionManager) } diff --git a/app/src/main/java/org/mozilla/fenix/components/toolbar/DefaultToolbarMenu.kt b/app/src/main/java/org/mozilla/fenix/components/toolbar/DefaultToolbarMenu.kt index 6c7a8d618e55..5003aaff843a 100644 --- a/app/src/main/java/org/mozilla/fenix/components/toolbar/DefaultToolbarMenu.kt +++ b/app/src/main/java/org/mozilla/fenix/components/toolbar/DefaultToolbarMenu.kt @@ -11,9 +11,9 @@ import mozilla.components.browser.menu.item.BrowserMenuHighlightableItem import mozilla.components.browser.menu.item.BrowserMenuImageText import mozilla.components.browser.menu.item.BrowserMenuItemToolbar import mozilla.components.browser.menu.item.BrowserMenuSwitch +import org.mozilla.fenix.browser.browsingmode.BrowsingMode import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.R -import org.mozilla.fenix.browser.browsingmode.BrowsingMode import org.mozilla.fenix.ext.asActivity import org.mozilla.fenix.ext.components import org.mozilla.fenix.theme.ThemeManager diff --git a/app/src/main/java/org/mozilla/fenix/customtabs/ExternalAppBrowserActivity.kt b/app/src/main/java/org/mozilla/fenix/customtabs/ExternalAppBrowserActivity.kt index ccee13230533..3332945af98c 100644 --- a/app/src/main/java/org/mozilla/fenix/customtabs/ExternalAppBrowserActivity.kt +++ b/app/src/main/java/org/mozilla/fenix/customtabs/ExternalAppBrowserActivity.kt @@ -5,8 +5,11 @@ package org.mozilla.fenix.customtabs import androidx.navigation.NavDestination +import androidx.navigation.NavDirections import mozilla.components.browser.session.runWithSession +import mozilla.components.concept.engine.manifest.WebAppManifestParser import mozilla.components.feature.intent.ext.getSessionId +import mozilla.components.feature.pwa.ext.getWebAppManifest import mozilla.components.support.utils.SafeIntent import org.mozilla.fenix.BrowserDirection import org.mozilla.fenix.HomeActivity @@ -22,6 +25,7 @@ import java.security.InvalidParameterException * such as custom tabs and progressive web apps. */ open class ExternalAppBrowserActivity : HomeActivity() { + final override fun getBreadcrumbMessage(destination: NavDestination): String { val fragmentName = resources.getResourceEntryName(destination.id) return "Changing to fragment $fragmentName, isCustomTab: true" @@ -34,12 +38,20 @@ open class ExternalAppBrowserActivity : HomeActivity() { override fun getNavDirections( from: BrowserDirection, customTabSessionId: String? - ) = when (from) { - BrowserDirection.FromGlobal -> - NavGraphDirections.actionGlobalExternalAppBrowser(customTabSessionId) - else -> throw InvalidParameterException( - "Tried to navigate to ExternalAppBrowserFragment from $from" - ) + ): NavDirections { + val manifest = intent + .getWebAppManifest() + ?.let { WebAppManifestParser().serialize(it).toString() } + return when (from) { + BrowserDirection.FromGlobal -> + NavGraphDirections.actionGlobalExternalAppBrowser( + activeSessionId = customTabSessionId, + webAppManifest = manifest + ) + else -> throw InvalidParameterException( + "Tried to navigate to ExternalAppBrowserFragment from $from" + ) + } } final override fun createBrowsingModeManager() = diff --git a/app/src/main/java/org/mozilla/fenix/customtabs/ExternalAppBrowserFragment.kt b/app/src/main/java/org/mozilla/fenix/customtabs/ExternalAppBrowserFragment.kt index 389c4e477cfd..41f41fbac396 100644 --- a/app/src/main/java/org/mozilla/fenix/customtabs/ExternalAppBrowserFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/customtabs/ExternalAppBrowserFragment.kt @@ -6,17 +6,25 @@ package org.mozilla.fenix.customtabs import android.view.Gravity import android.view.View +import androidx.core.view.isGone +import androidx.navigation.fragment.navArgs import kotlinx.android.synthetic.main.component_search.* import kotlinx.android.synthetic.main.fragment_browser.view.* import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ObsoleteCoroutinesApi import mozilla.components.browser.session.Session +import mozilla.components.concept.engine.manifest.WebAppManifestParser +import mozilla.components.concept.engine.manifest.getOrNull +import mozilla.components.feature.pwa.ext.getTrustedScope import mozilla.components.feature.pwa.ext.trustedOrigins +import mozilla.components.feature.pwa.feature.WebAppActivityFeature import mozilla.components.feature.pwa.feature.WebAppHideToolbarFeature +import mozilla.components.feature.pwa.feature.WebAppSiteControlsFeature import mozilla.components.feature.sitepermissions.SitePermissions import mozilla.components.lib.state.ext.consumeFrom import mozilla.components.support.base.feature.BackHandler import mozilla.components.support.base.feature.ViewBoundFeatureWrapper +import mozilla.components.support.ktx.android.arch.lifecycle.addObservers import org.mozilla.fenix.R import org.mozilla.fenix.browser.BaseBrowserFragment import org.mozilla.fenix.components.toolbar.BrowserToolbarController @@ -32,6 +40,8 @@ import org.mozilla.fenix.ext.requireComponents @ExperimentalCoroutinesApi class ExternalAppBrowserFragment : BaseBrowserFragment(), BackHandler { + private val args by navArgs() + private val customTabsIntegration = ViewBoundFeatureWrapper() private val hideToolbarFeature = ViewBoundFeatureWrapper() @@ -40,6 +50,11 @@ class ExternalAppBrowserFragment : BaseBrowserFragment(), BackHandler { val activity = requireActivity() val components = activity.components + val manifest = args.webAppManifest?.let { json -> + WebAppManifestParser().parse(json).getOrNull() + } + val trustedScopes = listOfNotNull(manifest?.getTrustedScope()) + customTabSessionId?.let { customTabSessionId -> customTabsIntegration.set( feature = CustomTabsIntegration( @@ -59,12 +74,29 @@ class ExternalAppBrowserFragment : BaseBrowserFragment(), BackHandler { requireComponents.core.sessionManager, toolbar, customTabSessionId, - emptyList() + trustedScopes ) { toolbarVisible -> updateLayoutMargins(inFullScreen = !toolbarVisible) }, owner = this, view = toolbar) + + if (manifest != null) { + activity.lifecycle.addObservers( + WebAppActivityFeature( + activity, + components.core.icons, + manifest + ), + WebAppSiteControlsFeature( + activity.applicationContext, + requireComponents.core.sessionManager, + requireComponents.useCases.sessionUseCases.reload, + customTabSessionId, + manifest + ) + ) + } } consumeFrom(browserStore) { @@ -121,8 +153,13 @@ class ExternalAppBrowserFragment : BaseBrowserFragment(), BackHandler { } override fun getEngineMargins(): Pair { - val toolbarSize = resources.getDimensionPixelSize(R.dimen.browser_toolbar_height) - return toolbarSize to 0 + val toolbarHidden = toolbar.isGone + return if (toolbarHidden) { + 0 to 0 + } else { + val toolbarSize = resources.getDimensionPixelSize(R.dimen.browser_toolbar_height) + toolbarSize to 0 + } } override fun getAppropriateLayoutGravity() = Gravity.TOP diff --git a/app/src/main/res/navigation/nav_graph.xml b/app/src/main/res/navigation/nav_graph.xml index 6525cd2ba9d2..f247ed989f5f 100644 --- a/app/src/main/res/navigation/nav_graph.xml +++ b/app/src/main/res/navigation/nav_graph.xml @@ -202,10 +202,8 @@ android:id="@+id/externalAppBrowserFragment" android:name="org.mozilla.fenix.customtabs.ExternalAppBrowserFragment" tools:layout="@layout/fragment_browser"> - + + diff --git a/buildSrc/src/main/java/Dependencies.kt b/buildSrc/src/main/java/Dependencies.kt index 38b3c9118c0b..9d8c875c0970 100644 --- a/buildSrc/src/main/java/Dependencies.kt +++ b/buildSrc/src/main/java/Dependencies.kt @@ -35,7 +35,7 @@ object Versions { const val androidx_work = "2.0.1" const val google_material = "1.1.0-alpha10" - const val mozilla_android_components = "14.0.1" + const val mozilla_android_components = "15.0.0-SNAPSHOT" // Note that android-components also depends on application-services, // and in fact is our main source of appservices-related functionality. // The version number below tracks the application-services version