Commit aa3fe6a4 authored by Tiger Oakes's avatar Tiger Oakes
Browse files

Closes #2383 - Update manifest of PWAs

parent 16eae533
Loading
Loading
Loading
Loading
+13 −2
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@ package mozilla.components.feature.pwa
import android.content.Context
import androidx.annotation.VisibleForTesting
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.withContext
import mozilla.components.concept.engine.manifest.WebAppManifest
import mozilla.components.feature.pwa.db.ManifestDatabase
@@ -33,7 +34,7 @@ class ManifestStorage(context: Context) {
    /**
     * Save a Web App Manifest to disk.
     */
    suspend fun saveManifest(manifest: WebAppManifest) = withContext(Dispatchers.IO) {
    suspend fun saveManifest(manifest: WebAppManifest) = withContext(IO) {
        val entity = ManifestEntity(
            manifest = manifest,
            updatedAt = System.currentTimeMillis(),
@@ -42,10 +43,20 @@ class ManifestStorage(context: Context) {
        manifestDao.value.insertManifest(entity)
    }

    /**
     * Update an existing Web App Manifest on disk.
     */
    suspend fun updateManifest(manifest: WebAppManifest) = withContext(IO) {
        manifestDao.value.getManifest(manifest.startUrl)?.let { existing ->
            val update = existing.copy(manifest = manifest, updatedAt = System.currentTimeMillis())
            manifestDao.value.updateManifest(update)
        }
    }

    /**
     * Delete all manifests associated with the list of URLs.
     */
    suspend fun removeManifests(startUrls: List<String>) = withContext(Dispatchers.IO) {
    suspend fun removeManifests(startUrls: List<String>) = withContext(IO) {
        manifestDao.value.deleteManifests(startUrls)
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -52,7 +52,7 @@ const val SHORTCUT_CATEGORY = "mozilla.components.pwa.category.SHORTCUT"
class WebAppShortcutManager(
    context: Context,
    httpClient: Client,
    private val storage: ManifestStorage = ManifestStorage(context),
    private val storage: ManifestStorage,
    internal val supportWebApps: Boolean = true
) {

+1 −0
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ class WebAppUseCases(
        WebAppShortcutManager(
            applicationContext,
            httpClient,
            storage = ManifestStorage(applicationContext),
            supportWebApps = supportWebApps
        )
    )
+5 −0
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@ import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Update

/**
 * Internal DAO for accessing [ManifestEntity] instances.
@@ -23,6 +24,10 @@ internal interface ManifestDao {
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    fun insertManifest(manifest: ManifestEntity): Long

    @WorkerThread
    @Update
    fun updateManifest(manifest: ManifestEntity)

    @WorkerThread
    @Query("DELETE FROM manifests WHERE start_url IN (:startUrls)")
    fun deleteManifests(startUrls: List<String>)
+72 −0
Original line number Diff line number Diff line
/* 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.feature.pwa.feature

import android.content.Context
import androidx.annotation.VisibleForTesting
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch
import mozilla.components.browser.session.Session
import mozilla.components.browser.session.SessionManager
import mozilla.components.concept.engine.manifest.WebAppManifest
import mozilla.components.feature.pwa.ManifestStorage
import mozilla.components.feature.pwa.WebAppShortcutManager
import mozilla.components.support.base.feature.LifecycleAwareFeature

/**
 * Feature used to update the existing web app manifest and web app shortcut.
 *
 * @param shortcutManager Shortcut manager used to update pinned shortcuts.
 * @param storage Manifest storage used to have updated manifests.
 * @param sessionId ID of the web app session to observe.
 * @param initialManifest Loaded manifest for the current web app.
 */
class ManifestUpdateFeature(
    private val applicationContext: Context,
    private val sessionManager: SessionManager,
    private val shortcutManager: WebAppShortcutManager,
    private val storage: ManifestStorage,
    private val sessionId: String,
    private var initialManifest: WebAppManifest
) : Session.Observer, LifecycleAwareFeature {

    private var scope: CoroutineScope? = null
    private var updateJob: Job? = null

    /**
     * When the manifest is changed, compare it to the existing manifest.
     * If it is different, update the disk and shortcut. Ignore if called with a null
     * manifest or a manifest with a different start URL.
     */
    override fun onWebAppManifestChanged(session: Session, manifest: WebAppManifest?) {
        if (manifest?.startUrl == initialManifest.startUrl && manifest != initialManifest) {
            updateJob?.cancel()
            updateJob = scope?.launch { updateStoredManifest(manifest) }
        }
    }

    /**
     * Updates the manifest on disk then updates the pinned shortcut to reflect changes.
     */
    @VisibleForTesting
    internal suspend fun updateStoredManifest(manifest: WebAppManifest) {
        storage.updateManifest(manifest)
        shortcutManager.updateShortcuts(applicationContext, listOf(manifest))
        initialManifest = manifest
    }

    override fun start() {
        scope = MainScope()
        sessionManager.findSessionById(sessionId)?.register(this)
    }

    override fun stop() {
        scope?.cancel()
        sessionManager.findSessionById(sessionId)?.unregister(this)
    }
}
Loading