Commit 793a62c6 authored by Sebastian Kaspari's avatar Sebastian Kaspari
Browse files

Closes #2290: Expose WebAppManifest in Session.

parent 8e3b1613
......@@ -6,6 +6,7 @@ package mozilla.components.browser.session
import android.graphics.Bitmap
import mozilla.components.browser.session.engine.EngineSessionHolder
import mozilla.components.browser.session.manifest.WebAppManifest
import mozilla.components.browser.session.tab.CustomTabConfig
import mozilla.components.concept.engine.HitResult
import mozilla.components.concept.engine.permission.PermissionRequest
......@@ -52,6 +53,7 @@ class Session(
fun onSearch(session: Session, searchTerms: String) = Unit
fun onSecurityChanged(session: Session, securityInfo: SecurityInfo) = Unit
fun onCustomTabConfigChanged(session: Session, customTabConfig: CustomTabConfig?) = Unit
fun onWebAppManifestChanged(session: Session, manifest: WebAppManifest?) = Unit
fun onDownload(session: Session, download: Download): Boolean = false
fun onTrackerBlockingEnabledChanged(session: Session, blockingEnabled: Boolean) = Unit
fun onTrackerBlocked(session: Session, blocked: String, all: List<String>) = Unit
......@@ -200,6 +202,13 @@ class Session(
_, _, new -> notifyObservers { onCustomTabConfigChanged(this@Session, new) }
}
/**
* The Web App Manifest for the currently visited page (or null).
*/
var webAppManifest: WebAppManifest? by Delegates.observable<WebAppManifest?>(null) {
_, _, new -> notifyObservers { onWebAppManifestChanged(this@Session, new) }
}
/**
* Last download request if it wasn't consumed by at least one observer.
*/
......
/* 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 mozilla.components.browser.session.manifest
/**
* The web app manifest provides information about an application (such as its name, author, icon, and description).
*
* Web app manifests are part of a collection of web technologies called progressive web apps, which are websites
* that can be installed to a device’s homescreen without an app store, along with other capabilities like working
* offline and receiving push notifications.
*
* https://developer.mozilla.org/en-US/docs/Web/Manifest
* https://www.w3.org/TR/appmanifest/
* https://developers.google.com/web/fundamentals/web-app-manifest/
*
* @property name Provides a human-readable name for the site when displayed to the user. For example, among a list of
* other applications or as a label for an icon.
* @property shortName Provides a short human-readable name for the application. This is intended for when there is
* insufficient space to display the full name of the web application, like device homescreens.
* @property startUrl The URL that loads when a user launches the application (e.g. when added to home screen),
* typically the index. Note that this has to be a relative URL, relative to the manifest url.
* @property display Defines the developers’ preferred display mode for the website.
* @property backgroundColor Defines the expected “background color” for the website. This value repeats what is
* already available in the site’s CSS, but can be used by browsers to draw the background color of a shortcut when
* the manifest is available before the stylesheet has loaded. This creates a smooth transition between launching the
* web application and loading the site's content.
* @property description Provides a general description of what the pinned website does.
* @property icons Specifies a list of image files that can serve as application icons, depending on context. For
* example, they can be used to represent the web application amongst a list of other applications, or to integrate the
* web application with an OS's task switcher and/or system preferences.
* @property dir Specifies the primary text direction for the name, short_name, and description members. Together with
* the lang member, it helps the correct display of right-to-left languages.
* @property lang Specifies the primary language for the values in the name and short_name members. This value is a
* string containing a single language tag (e.g. en-US).
* @property orientation Defines the default orientation for all the website's top level browsing contexts.
* @property scope Defines the navigation scope of this website's context. This restricts what web pages can be viewed
* while the manifest is applied. If the user navigates outside the scope, it returns to a normal web page inside a
* browser tab/window.
* @property themeColor Defines the default theme color for an application. This sometimes affects how the OS displays
* the site (e.g., on Android's task switcher, the theme color surrounds the site).
*/
data class WebAppManifest(
val name: String,
val startUrl: String,
val shortName: String? = null,
val display: DisplayMode = DisplayMode.BROWSER,
val backgroundColor: Int? = null,
val description: String? = null,
val icons: List<Icon> = emptyList(),
val dir: TextDirection = TextDirection.AUTO,
val lang: String? = null,
val orientation: Orientation = Orientation.ANY,
val scope: String? = null,
val themeColor: Int? = null
) {
/**
* Defines the developers’ preferred display mode for the website.
*/
enum class DisplayMode {
/**
* All of the available display area is used and no user agent chrome is shown.
*/
FULLSCREEN,
/**
* The application will look and feel like a standalone application. This can include the application having a
* different window, its own icon in the application launcher, etc. In this mode, the user agent will exclude
* UI elements for controlling navigation, but can include other UI elements such as a status bar.
*/
STANDALONE,
/**
* The application will look and feel like a standalone application, but will have a minimal set of UI elements
* for controlling navigation. The elements will vary by browser.
*/
MINIMAL_UI,
/**
* The application opens in a conventional browser tab or new window, depending on the browser and platform.
* This is the default.
*/
BROWSER
}
/**
* An image file that can serve as application icon.
*
* @property src The path to the image file. If src is a relative URL, the base URL will be the URL of the manifest.
* @property sizes A list of image dimensions.
* @property type A hint as to the media type of the image. The purpose of this member is to allow a user agent to
* quickly ignore images of media types it does not support.
* @property purpose Defines the purpose of the image, for example that the image is intended to serve some special
* purpose in the context of the host OS (i.e., for better integration).
*/
data class Icon(
val src: String,
val sizes: List<Size>,
val type: String,
val purpose: Purpose = Purpose.ANY
) {
enum class Purpose {
/**
* A user agent can present this icon where space constraints and/or color requirements differ from those
* of the application icon.
*/
BADGE,
/**
* The image is designed with icon masks and safe zone in mind, such that any part of the image that is
* outside the safe zone can safely be ignored and masked away by the user agent.
*
* https://w3c.github.io/manifest/#icon-masks
*/
MASKABLE,
/**
* The user agent is free to display the icon in any context (this is the default value).
*/
ANY
}
data class Size(
val width: Int,
val height: Int
)
}
/**
* Defines the default orientation for all the website's top level browsing contexts.
*/
enum class Orientation {
ANY,
NATURAL,
LANDSCAPE,
LANDSCAPE_PRIMARY,
LANDSCAPE_SECONDARY,
PORTRAIT,
PORTRAIT_PRIMARY,
PORTRAIT_SECONDARY
}
/**
* Specifies the primary text direction for the name, short_name, and description members. Together with the lang
* member, it helps the correct display of right-to-left languages.
*/
enum class TextDirection {
/**
* Left-to-right (LTR).
*/
LTR,
/**
* Right-to-left (RTL).
*/
RTL,
/**
* If the value is set to auto, the browser will use the Unicode bidirectional algorithm to make a best guess
* about the text's direction.
*/
AUTO
}
}
......@@ -10,6 +10,7 @@ import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.async
import kotlinx.coroutines.runBlocking
import mozilla.components.browser.session.Session.Source
import mozilla.components.browser.session.manifest.WebAppManifest
import mozilla.components.browser.session.tab.CustomTabConfig
import mozilla.components.concept.engine.HitResult
import mozilla.components.concept.engine.permission.PermissionRequest
......@@ -17,6 +18,7 @@ import mozilla.components.concept.engine.prompt.PromptRequest
import mozilla.components.concept.engine.window.WindowRequest
import mozilla.components.support.base.observer.Consumable
import mozilla.components.support.test.any
import mozilla.components.support.test.argumentCaptor
import mozilla.components.support.test.eq
import mozilla.components.support.test.mock
import org.junit.Assert.assertEquals
......@@ -206,6 +208,37 @@ class SessionTest {
assertEquals("id", config!!.id)
}
@Test
fun `observer is notified when web app manifest is set`() {
val manifest = WebAppManifest(
name = "HackerWeb",
description = "A simply readable Hacker News app.",
startUrl = ".",
display = WebAppManifest.DisplayMode.STANDALONE,
icons = listOf(
WebAppManifest.Icon(
src = "images/touch/homescreen192.png",
sizes = listOf(WebAppManifest.Icon.Size(192, 192)),
type = "image/png"
)
)
)
val observer: Session.Observer = mock()
val session = Session("https://www.mozilla.org")
session.register(observer)
assertNull(session.webAppManifest)
session.webAppManifest = manifest
assertEquals(manifest, session.webAppManifest)
val captor = argumentCaptor<WebAppManifest>()
verify(observer).onWebAppManifestChanged(eq(session), captor.capture())
assertEquals(manifest, captor.value)
}
@Test
fun `session returns initial URL`() {
val session = Session("https://www.mozilla.org")
......@@ -571,6 +604,7 @@ class SessionTest {
defaultObserver.onPromptRequested(session, promptRequest)
defaultObserver.onOpenWindowRequested(session, windowRequest)
defaultObserver.onCloseWindowRequested(session, windowRequest)
defaultObserver.onWebAppManifestChanged(session, mock())
}
@Test
......@@ -746,4 +780,10 @@ class SessionTest {
}
}
}
@Test
fun `toString returns string containing id and url`() {
val session = Session(id = "my-session-id", initialUrl = "https://www.mozilla.org")
assertEquals("Session(my-session-id, https://www.mozilla.org)", session.toString())
}
}
......@@ -12,6 +12,9 @@ permalink: /changelog/
* [Gecko](https://github.com/mozilla-mobile/android-components/blob/master/buildSrc/src/main/java/Gecko.kt)
* [Configuration](https://github.com/mozilla-mobile/android-components/blob/master/buildSrc/src/main/java/Config.kt)
* **browser-session**
* Added `Session.webAppManifest` to expose the [Web App Manifest](https://developer.mozilla.org/en-US/docs/Web/Manifest) of the currently visible page. This functionality will only be available in [GeckoView](https://mozilla.github.io/geckoview/)-flavored [concept-engine](https://github.com/mozilla-mobile/android-components/tree/master/components/concept/engine) implementations.
# 0.46.0-SNAPSHOT
* [Commits](https://github.com/mozilla-mobile/android-components/compare/v0.45.0...v0.46.0)
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment