Skip to content

Commit

Permalink
Issue mozilla-mobile#4278: (Merge day) browser-engine-gecko-beta (69)…
Browse files Browse the repository at this point in the history
… -> browser-engine-gecko-release (69)
  • Loading branch information
pocmo committed Sep 3, 2019
1 parent 648ed1c commit e0d4140
Show file tree
Hide file tree
Showing 19 changed files with 317 additions and 103 deletions.
2 changes: 1 addition & 1 deletion buildSrc/src/main/java/Gecko.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ internal object GeckoVersions {
/**
* GeckoView Release Version.
*/
const val release_version = "68.0.20190711090008"
const val release_version = "69.0.20190903125908"
}

@Suppress("MaxLineLength")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ import mozilla.components.browser.engine.gecko.mediaquery.toGeckoValue
import mozilla.components.browser.engine.gecko.webextension.GeckoWebExtension
import mozilla.components.concept.engine.Engine
import mozilla.components.concept.engine.EngineSession
import mozilla.components.concept.engine.EngineSession.TrackingProtectionPolicy
import mozilla.components.concept.engine.EngineSession.SafeBrowsingPolicy
import mozilla.components.concept.engine.EngineSession.TrackingProtectionPolicy
import mozilla.components.concept.engine.EngineSessionState
import mozilla.components.concept.engine.EngineView
import mozilla.components.concept.engine.Settings
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import android.annotation.SuppressLint
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import mozilla.components.browser.engine.gecko.media.GeckoMediaDelegate
import mozilla.components.browser.engine.gecko.permission.GeckoPermissionRequest
Expand All @@ -18,15 +17,18 @@ import mozilla.components.concept.engine.EngineSession
import mozilla.components.concept.engine.EngineSessionState
import mozilla.components.concept.engine.HitResult
import mozilla.components.concept.engine.Settings
import mozilla.components.concept.engine.content.blocking.Tracker
import mozilla.components.concept.engine.history.HistoryTrackingDelegate
import mozilla.components.concept.engine.manifest.WebAppManifestParser
import mozilla.components.concept.engine.request.RequestInterceptor
import mozilla.components.concept.engine.content.blocking.Tracker
import mozilla.components.concept.engine.request.RequestInterceptor.InterceptionResponse
import mozilla.components.concept.storage.VisitType
import mozilla.components.support.ktx.android.util.Base64
import mozilla.components.support.ktx.kotlin.isEmail
import mozilla.components.support.ktx.kotlin.isGeoLocation
import mozilla.components.support.ktx.kotlin.isPhone
import mozilla.components.support.utils.DownloadUtils
import org.json.JSONObject
import org.mozilla.geckoview.AllowOrDeny
import org.mozilla.geckoview.ContentBlocking
import org.mozilla.geckoview.GeckoResult
Expand Down Expand Up @@ -321,8 +323,9 @@ class GeckoEngineSession(
GeckoResult.fromValue(AllowOrDeny.DENY)
} else {
notifyObservers {
// As the name LoadRequest.isRedirect may imply this flag is about http redirects. The flag
// Unlike the name LoadRequest.isRedirect may imply this flag is not about http redirects. The flag
// is "True if and only if the request was triggered by an HTTP redirect."
// See: https://bugzilla.mozilla.org/show_bug.cgi?id=1545170
onLoadRequest(
url = request.uri,
triggeredByRedirect = request.isRedirect,
Expand Down Expand Up @@ -450,12 +453,10 @@ class GeckoEngineSession(
return GeckoResult.fromValue(false)
}

val result = GeckoResult<Boolean>()
launch {
return launchGeckoResult {
delegate.onVisited(url, visitType)
result.complete(true)
true
}
return result
}

override fun getVisited(
Expand All @@ -468,12 +469,10 @@ class GeckoEngineSession(

val delegate = settings.historyTrackingDelegate ?: return GeckoResult.fromValue(null)

val result = GeckoResult<BooleanArray>()
launch {
val visits: List<Boolean>? = delegate.getVisited(urls.toList())
result.complete(visits?.toBooleanArray())
return launchGeckoResult {
val visits = delegate.getVisited(urls.toList())
visits.toBooleanArray()
}
return result
}
}

Expand All @@ -496,23 +495,48 @@ class GeckoEngineSession(
override fun onCrash(session: GeckoSession) {
stateBeforeCrash = lastSessionState

geckoSession.close()
createGeckoSession()
recoverGeckoSession()

notifyObservers { onCrash() }
}

override fun onKill(session: GeckoSession) {
// The content process of this session got killed (resources reclaimed by Android).
// Let's recover and restore the last known state.

val state = lastSessionState

recoverGeckoSession()

state?.let { geckoSession.restoreState(it) }

notifyObservers { onProcessKilled() }
}

private fun recoverGeckoSession() {
// Recover the GeckoSession after the process getting killed or crashing. We create a
// new underlying GeckoSession.
// Eventually we may be able to re-use the same GeckoSession by re-opening it. However
// that seems to have caused issues:
// https://github.com/mozilla-mobile/android-components/issues/3640

geckoSession.close()
createGeckoSession()
}

override fun onFullScreen(session: GeckoSession, fullScreen: Boolean) {
notifyObservers { onFullScreenChange(fullScreen) }
}

override fun onExternalResponse(session: GeckoSession, response: GeckoSession.WebResponseInfo) {
notifyObservers {
val fileName = response.filename
?: DownloadUtils.guessFileName(null, response.uri, response.contentType)
onExternalResource(
url = response.uri,
contentLength = response.contentLength,
contentType = response.contentType,
fileName = response.filename)
fileName = fileName)
}
}

Expand All @@ -532,6 +556,13 @@ class GeckoEngineSession(
}

override fun onFocusRequest(session: GeckoSession) = Unit

override fun onWebAppManifest(session: GeckoSession, manifest: JSONObject) {
val parsed = WebAppManifestParser().parse(manifest)
if (parsed is WebAppManifestParser.Result.Success) {
notifyObservers { onWebAppManifestLoaded(parsed.manifest) }
}
}
}

private fun createContentBlockingDelegate() = object : ContentBlocking.Delegate {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ class GeckoEngineView @JvmOverloads constructor(
override fun onCrash() {
rebind()
}

override fun onProcessKilled() {
rebind()
}

override fun onAppPermissionRequest(permissionRequest: PermissionRequest) = Unit
override fun onContentPermissionRequest(permissionRequest: PermissionRequest) = Unit
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/* 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.engine.gecko

import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.launch
import org.mozilla.geckoview.GeckoResult
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine

/**
* Wait for a GeckoResult to be complete in a co-routine.
*/
suspend fun <T> GeckoResult<T>.await() = suspendCoroutine<T?> { continuation ->
then({
continuation.resume(it)
GeckoResult<Void>()
}, {
continuation.resumeWithException(it)
GeckoResult<Void>()
})
}

/**
* Create a GeckoResult from a co-routine.
*/
@Suppress("TooGenericExceptionCaught")
fun <T> CoroutineScope.launchGeckoResult(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> T
) = GeckoResult<T>().apply {
launch(context, start) {
try {
val value = block()
complete(value)
} catch (exception: Throwable) {
completeExceptionally(exception)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,23 +38,15 @@ class GeckoViewFetchClient(
internal var executor: GeckoWebExecutor = GeckoWebExecutor(runtime)

@Throws(IOException::class)
@Suppress("ComplexMethod")
override fun fetch(request: Request): Response {
val webRequest = with(request) {
WebRequest.Builder(url)
.method(method.name)
.addHeadersFrom(request, defaultHeaders)
.addBodyFrom(request)
.cacheMode(if (request.useCaches) CACHE_MODE_DEFAULT else CACHE_MODE_RELOAD)
.build()
}
val webRequest = request.toWebRequest(defaultHeaders)

val readTimeOut = request.readTimeout ?: maxReadTimeOut
val readTimeOutMillis = readTimeOut.let { (timeout, unit) ->
unit.toMillis(timeout)
}

try {
return try {
var fetchFlags = 0
if (request.cookiePolicy == Request.CookiePolicy.OMIT) {
fetchFlags += GeckoWebExecutor.FETCH_FLAGS_ANONYMOUS
Expand All @@ -63,7 +55,7 @@ class GeckoViewFetchClient(
fetchFlags += GeckoWebExecutor.FETCH_FLAGS_NO_REDIRECTS
}
val webResponse = executor.fetch(webRequest, fetchFlags).poll(readTimeOutMillis)
return webResponse?.toResponse() ?: throw IOException("Fetch failed with null response")
webResponse?.toResponse() ?: throw IOException("Fetch failed with null response")
} catch (e: TimeoutException) {
throw SocketTimeoutException()
} catch (e: WebRequestError) {
Expand All @@ -76,6 +68,13 @@ class GeckoViewFetchClient(
}
}

private fun Request.toWebRequest(defaultHeaders: Headers): WebRequest = WebRequest.Builder(url)
.method(method.name)
.addHeadersFrom(this, defaultHeaders)
.addBodyFrom(this)
.cacheMode(if (useCaches) CACHE_MODE_DEFAULT else CACHE_MODE_RELOAD)
.build()

private fun WebRequest.Builder.addHeadersFrom(request: Request, defaultHeaders: Headers): WebRequest.Builder {
defaultHeaders.filter { header ->
request.headers?.contains(header.name) != true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ internal class GeckoMedia(
private class MediaDelegate(
private val media: GeckoMedia
) : MediaElement.Delegate {
@Suppress("ComplexMethod")

override fun onPlaybackStateChange(mediaElement: MediaElement, mediaState: Int) {
when (mediaState) {
MEDIA_STATE_PLAY -> media.playbackState = Media.PlaybackState.PLAY
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,11 @@ internal class GeckoMediaDelegate(
private val mediaMap: MutableMap<MediaElement, Media> = mutableMapOf()

override fun onMediaAdd(session: GeckoSession, element: MediaElement) {
engineSession.notifyObservers {
val media = GeckoMedia(element)

mediaMap[element] = media

onMediaAdded(media)
val media = GeckoMedia(element).also {
mediaMap[element] = it
}

engineSession.notifyObservers { onMediaAdded(media) }
}

override fun onMediaRemove(session: GeckoSession, element: MediaElement) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,21 @@

package mozilla.components.browser.engine.gecko.permission

import android.Manifest.permission.ACCESS_COARSE_LOCATION
import android.Manifest.permission.ACCESS_FINE_LOCATION
import android.Manifest.permission.CAMERA
import android.Manifest.permission.RECORD_AUDIO
import mozilla.components.concept.engine.permission.Permission
import mozilla.components.concept.engine.permission.PermissionRequest
import org.mozilla.geckoview.GeckoSession.PermissionDelegate
import org.mozilla.geckoview.GeckoSession.PermissionDelegate.PERMISSION_GEOLOCATION
import org.mozilla.geckoview.GeckoSession.PermissionDelegate.PERMISSION_DESKTOP_NOTIFICATION
import org.mozilla.geckoview.GeckoSession.PermissionDelegate.MediaSource
import org.mozilla.geckoview.GeckoSession.PermissionDelegate.MediaSource.SOURCE_AUDIOCAPTURE
import org.mozilla.geckoview.GeckoSession.PermissionDelegate.MediaSource.SOURCE_APPLICATION
import org.mozilla.geckoview.GeckoSession.PermissionDelegate.MediaSource.SOURCE_BROWSER
import org.mozilla.geckoview.GeckoSession.PermissionDelegate.MediaSource.SOURCE_CAMERA
import org.mozilla.geckoview.GeckoSession.PermissionDelegate.MediaSource.SOURCE_MICROPHONE
import org.mozilla.geckoview.GeckoSession.PermissionDelegate.MediaSource.SOURCE_OTHER
import org.mozilla.geckoview.GeckoSession.PermissionDelegate.MediaSource.SOURCE_SCREEN
import org.mozilla.geckoview.GeckoSession.PermissionDelegate.MediaSource.SOURCE_WINDOW
import android.Manifest.permission.ACCESS_COARSE_LOCATION
import android.Manifest.permission.ACCESS_FINE_LOCATION
import android.Manifest.permission.CAMERA
import android.Manifest.permission.RECORD_AUDIO
import org.mozilla.geckoview.GeckoSession.PermissionDelegate.PERMISSION_DESKTOP_NOTIFICATION
import org.mozilla.geckoview.GeckoSession.PermissionDelegate.PERMISSION_GEOLOCATION

/**
* Gecko-based implementation of [PermissionRequest].
Expand Down Expand Up @@ -118,26 +115,27 @@ sealed class GeckoPermissionRequest constructor(
}

companion object {
@Suppress("ComplexMethod", "SwitchIntDef")
fun mapPermission(mediaSource: MediaSource): Permission {
fun mapPermission(mediaSource: MediaSource): Permission =
if (mediaSource.type == MediaSource.TYPE_AUDIO) {
return when (mediaSource.source) {
SOURCE_AUDIOCAPTURE -> Permission.ContentAudioCapture(mediaSource.id, mediaSource.name)
SOURCE_MICROPHONE -> Permission.ContentAudioMicrophone(mediaSource.id, mediaSource.name)
SOURCE_OTHER -> Permission.ContentAudioOther(mediaSource.id, mediaSource.name)
else -> Permission.Generic(mediaSource.id, mediaSource.name)
}
mapAudioPermission(mediaSource)
} else {
return when (mediaSource.source) {
SOURCE_CAMERA -> Permission.ContentVideoCamera(mediaSource.id, mediaSource.name)
SOURCE_APPLICATION -> Permission.ContentVideoApplication(mediaSource.id, mediaSource.name)
SOURCE_BROWSER -> Permission.ContentVideoBrowser(mediaSource.id, mediaSource.name)
SOURCE_SCREEN -> Permission.ContentVideoScreen(mediaSource.id, mediaSource.name)
SOURCE_WINDOW -> Permission.ContentVideoWindow(mediaSource.id, mediaSource.name)
SOURCE_OTHER -> Permission.ContentVideoOther(mediaSource.id, mediaSource.name)
else -> Permission.Generic(mediaSource.id, mediaSource.name)
}
mapVideoPermission(mediaSource)
}

@Suppress("SwitchIntDef")
private fun mapAudioPermission(mediaSource: MediaSource) = when (mediaSource.source) {
SOURCE_AUDIOCAPTURE -> Permission.ContentAudioCapture(mediaSource.id, mediaSource.name)
SOURCE_MICROPHONE -> Permission.ContentAudioMicrophone(mediaSource.id, mediaSource.name)
SOURCE_OTHER -> Permission.ContentAudioOther(mediaSource.id, mediaSource.name)
else -> Permission.Generic(mediaSource.id, mediaSource.name)
}

@Suppress("ComplexMethod", "SwitchIntDef")
private fun mapVideoPermission(mediaSource: MediaSource) = when (mediaSource.source) {
SOURCE_CAMERA -> Permission.ContentVideoCamera(mediaSource.id, mediaSource.name)
SOURCE_SCREEN -> Permission.ContentVideoScreen(mediaSource.id, mediaSource.name)
SOURCE_OTHER -> Permission.ContentVideoOther(mediaSource.id, mediaSource.name)
else -> Permission.Generic(mediaSource.id, mediaSource.name)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@ internal class GeckoPromptDelegate(private val geckoEngineSession: GeckoEngineSe

val isMultipleFilesSelection = selectionType == GeckoSession.PromptDelegate.FILE_TYPE_MULTIPLE

val captureMode = PromptRequest.File.FacingMode.NONE

val onSelectSingle: (Context, Uri) -> Unit = { context, uri ->
callback.confirm(context, uri.toFileUri(context))
}
Expand All @@ -145,6 +147,7 @@ internal class GeckoPromptDelegate(private val geckoEngineSession: GeckoEngineSe
PromptRequest.File(
mimeTypes ?: emptyArray(),
isMultipleFilesSelection,
captureMode,
onSelectSingle,
onSelectMultiple,
onDismiss
Expand Down
Loading

0 comments on commit e0d4140

Please sign in to comment.