good state
This commit is contained in:
+5
-167
@@ -1,171 +1,20 @@
|
||||
package eu.lensai.flutter_mozilla_components
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.view.View
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import eu.lensai.flutter_mozilla_components.activities.NotificationActivity
|
||||
import eu.lensai.flutter_mozilla_components.api.GeckoAddonsApiImpl
|
||||
import eu.lensai.flutter_mozilla_components.api.GeckoBrowserApiImpl
|
||||
import eu.lensai.flutter_mozilla_components.api.GeckoContainerProxyApiImpl
|
||||
import eu.lensai.flutter_mozilla_components.api.GeckoCookieApiImpl
|
||||
import eu.lensai.flutter_mozilla_components.api.GeckoDeleteBrowsingDataControllerImpl
|
||||
import eu.lensai.flutter_mozilla_components.api.GeckoDownloadsApiImpl
|
||||
import eu.lensai.flutter_mozilla_components.api.GeckoEngineSettingsApiImpl
|
||||
import eu.lensai.flutter_mozilla_components.api.GeckoFindApiImpl
|
||||
import eu.lensai.flutter_mozilla_components.api.GeckoIconsApiImpl
|
||||
import eu.lensai.flutter_mozilla_components.api.GeckoPrefApiImpl
|
||||
import eu.lensai.flutter_mozilla_components.api.GeckoSelectionActionControllerImpl
|
||||
import eu.lensai.flutter_mozilla_components.api.GeckoSessionApiImpl
|
||||
import eu.lensai.flutter_mozilla_components.api.GeckoSuggestionApiImpl
|
||||
import eu.lensai.flutter_mozilla_components.api.GeckoTabsApiImpl
|
||||
import eu.lensai.flutter_mozilla_components.api.GeckoBrowserExtensionApiImpl
|
||||
import eu.lensai.flutter_mozilla_components.feature.DefaultSelectionActionDelegate
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.BrowserExtensionEvents
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.GeckoAddonEvents
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.GeckoAddonsApi
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.GeckoBrowserApi
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.GeckoBrowserExtensionApi
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.GeckoContainerProxyApi
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.GeckoCookieApi
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.GeckoDeleteBrowsingDataController
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.GeckoDownloadsApi
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.GeckoEngineSettingsApi
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.GeckoFindApi
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.GeckoIconsApi
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.GeckoPrefApi
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.GeckoSelectionActionController
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.GeckoSelectionActionEvents
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.GeckoSessionApi
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.GeckoStateEvents
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.GeckoSuggestionApi
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.GeckoSuggestionEvents
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.GeckoTabContentEvents
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.GeckoTabsApi
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.ReaderViewController
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.ReaderViewEvents
|
||||
|
||||
import io.flutter.embedding.engine.plugins.FlutterPlugin
|
||||
import io.flutter.embedding.engine.plugins.activity.ActivityAware
|
||||
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
|
||||
import mozilla.components.support.base.log.Log
|
||||
import mozilla.components.support.base.log.sink.AndroidLogSink
|
||||
|
||||
|
||||
/** FlutterMozillaComponentsPlugin */
|
||||
class FlutterMozillaComponentsPlugin: FlutterPlugin, ActivityAware {
|
||||
companion object {
|
||||
private const val FRAGMENT_CONTAINER_ID = 0xBEEF
|
||||
|
||||
private var isGeckoInitialized = false
|
||||
}
|
||||
|
||||
private val components by lazy {
|
||||
requireNotNull(GlobalComponents.components) { "Components not initialized" }
|
||||
}
|
||||
|
||||
private var activity: Activity? = null
|
||||
|
||||
private lateinit var _flutterPluginBinding: FlutterPlugin.FlutterPluginBinding;
|
||||
private lateinit var _flutterEvents : GeckoStateEvents
|
||||
|
||||
private var isPlatformViewRegistered = false
|
||||
private val browserApi = GeckoBrowserApiImpl()
|
||||
|
||||
override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
|
||||
synchronized(this) {
|
||||
if(!isGeckoInitialized) {
|
||||
Log.addSink(AndroidLogSink())
|
||||
|
||||
setupGeckoEngine(flutterPluginBinding)
|
||||
isGeckoInitialized = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupGeckoEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
|
||||
_flutterPluginBinding = flutterPluginBinding
|
||||
|
||||
_flutterEvents = GeckoStateEvents(_flutterPluginBinding.binaryMessenger)
|
||||
val selectionActionEvents = GeckoSelectionActionEvents(_flutterPluginBinding.binaryMessenger)
|
||||
|
||||
val selectionActionDelegate = DefaultSelectionActionDelegate(selectionActionEvents)
|
||||
|
||||
val readerViewController =
|
||||
ReaderViewController(_flutterPluginBinding.binaryMessenger)
|
||||
|
||||
val extensionEvents = BrowserExtensionEvents(_flutterPluginBinding.binaryMessenger)
|
||||
|
||||
val addonEvents = GeckoAddonEvents(_flutterPluginBinding.binaryMessenger)
|
||||
val tabContentEvents = GeckoTabContentEvents(_flutterPluginBinding.binaryMessenger)
|
||||
|
||||
val suggestionEvents = GeckoSuggestionEvents(_flutterPluginBinding.binaryMessenger)
|
||||
GeckoSuggestionApi.setUp(_flutterPluginBinding.binaryMessenger, GeckoSuggestionApiImpl(suggestionEvents))
|
||||
|
||||
GlobalComponents.setUp(
|
||||
flutterPluginBinding.applicationContext,
|
||||
_flutterEvents,
|
||||
readerViewController,
|
||||
selectionActionDelegate,
|
||||
addonEvents,
|
||||
tabContentEvents,
|
||||
extensionEvents
|
||||
)
|
||||
|
||||
GeckoBrowserApi.setUp(_flutterPluginBinding.binaryMessenger, GeckoBrowserApiImpl {
|
||||
showNativeFragment()
|
||||
})
|
||||
|
||||
GeckoEngineSettingsApi.setUp(_flutterPluginBinding.binaryMessenger, GeckoEngineSettingsApiImpl())
|
||||
GeckoAddonsApi.setUp(_flutterPluginBinding.binaryMessenger, GeckoAddonsApiImpl(flutterPluginBinding.applicationContext))
|
||||
GeckoSessionApi.setUp(_flutterPluginBinding.binaryMessenger, GeckoSessionApiImpl())
|
||||
GeckoTabsApi.setUp(_flutterPluginBinding.binaryMessenger, GeckoTabsApiImpl())
|
||||
GeckoIconsApi.setUp(_flutterPluginBinding.binaryMessenger, GeckoIconsApiImpl())
|
||||
GeckoCookieApi.setUp(_flutterPluginBinding.binaryMessenger, GeckoCookieApiImpl())
|
||||
GeckoPrefApi.setUp(_flutterPluginBinding.binaryMessenger, GeckoPrefApiImpl())
|
||||
GeckoContainerProxyApi.setUp(_flutterPluginBinding.binaryMessenger, GeckoContainerProxyApiImpl())
|
||||
GeckoFindApi.setUp(_flutterPluginBinding.binaryMessenger, GeckoFindApiImpl())
|
||||
GeckoSelectionActionController.setUp(_flutterPluginBinding.binaryMessenger, GeckoSelectionActionControllerImpl(
|
||||
selectionActionDelegate
|
||||
))
|
||||
GeckoDeleteBrowsingDataController.setUp(_flutterPluginBinding.binaryMessenger, GeckoDeleteBrowsingDataControllerImpl())
|
||||
GeckoDownloadsApi.setUp(_flutterPluginBinding.binaryMessenger, GeckoDownloadsApiImpl())
|
||||
GeckoBrowserExtensionApi.setUp(_flutterPluginBinding.binaryMessenger, GeckoBrowserExtensionApiImpl())
|
||||
|
||||
ReaderViewEvents.setUp(
|
||||
_flutterPluginBinding.binaryMessenger,
|
||||
components.events.readerViewEvents
|
||||
)
|
||||
|
||||
val intent = Intent(flutterPluginBinding.applicationContext, NotificationActivity::class.java)
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
flutterPluginBinding.applicationContext.startActivity(intent)
|
||||
}
|
||||
|
||||
private fun showNativeFragment(): Boolean {
|
||||
if (!isPlatformViewRegistered) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (activity == null || activity !is FragmentActivity) {
|
||||
return false
|
||||
}
|
||||
|
||||
val fragmentActivity = activity as FragmentActivity
|
||||
|
||||
// Check if the container view exists in the view hierarchy
|
||||
val container = fragmentActivity.findViewById<View>(FRAGMENT_CONTAINER_ID)
|
||||
if (container == null) {
|
||||
// Container doesn't exist yet, retry later
|
||||
return false
|
||||
}
|
||||
|
||||
val nativeFragment = BrowserFragment.create()
|
||||
val fm = fragmentActivity.supportFragmentManager
|
||||
fm.beginTransaction()
|
||||
.replace(FRAGMENT_CONTAINER_ID, nativeFragment)
|
||||
.commitAllowingStateLoss()
|
||||
|
||||
return true
|
||||
browserApi.attachBinding(flutterPluginBinding)
|
||||
GeckoBrowserApi.setUp(flutterPluginBinding.binaryMessenger, browserApi)
|
||||
}
|
||||
|
||||
override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
|
||||
@@ -173,17 +22,7 @@ class FlutterMozillaComponentsPlugin: FlutterPlugin, ActivityAware {
|
||||
}
|
||||
|
||||
override fun onAttachedToActivity(binding: ActivityPluginBinding) {
|
||||
this.activity = binding.activity
|
||||
|
||||
_flutterPluginBinding.platformViewRegistry.registerViewFactory(
|
||||
"eu.lensai/gecko", GeckoViewFactory(
|
||||
binding.activity,
|
||||
FRAGMENT_CONTAINER_ID,
|
||||
_flutterEvents
|
||||
)
|
||||
)
|
||||
|
||||
isPlatformViewRegistered = true
|
||||
browserApi.attachActivity(binding.activity)
|
||||
}
|
||||
|
||||
override fun onDetachedFromActivityForConfigChanges() {
|
||||
@@ -195,7 +34,6 @@ class FlutterMozillaComponentsPlugin: FlutterPlugin, ActivityAware {
|
||||
}
|
||||
|
||||
override fun onDetachedFromActivity() {
|
||||
this.activity = null
|
||||
isPlatformViewRegistered = false
|
||||
browserApi.detachActivity()
|
||||
}
|
||||
}
|
||||
|
||||
+162
-1
@@ -1,17 +1,99 @@
|
||||
package eu.lensai.flutter_mozilla_components.api
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.view.View
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import eu.lensai.flutter_mozilla_components.BrowserFragment
|
||||
import eu.lensai.flutter_mozilla_components.GeckoViewFactory
|
||||
import eu.lensai.flutter_mozilla_components.GlobalComponents
|
||||
import eu.lensai.flutter_mozilla_components.activities.NotificationActivity
|
||||
import eu.lensai.flutter_mozilla_components.feature.DefaultSelectionActionDelegate
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.BrowserExtensionEvents
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.GeckoAddonEvents
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.GeckoAddonsApi
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.GeckoBrowserApi
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.GeckoBrowserExtensionApi
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.GeckoContainerProxyApi
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.GeckoCookieApi
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.GeckoDeleteBrowsingDataController
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.GeckoDownloadsApi
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.GeckoEngineSettingsApi
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.GeckoFindApi
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.GeckoIconsApi
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.GeckoPrefApi
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.GeckoSelectionActionController
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.GeckoSelectionActionEvents
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.GeckoSessionApi
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.GeckoStateEvents
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.GeckoSuggestionApi
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.GeckoSuggestionEvents
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.GeckoTabContentEvents
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.GeckoTabsApi
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.ReaderViewController
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.ReaderViewEvents
|
||||
import io.flutter.embedding.engine.plugins.FlutterPlugin
|
||||
import io.flutter.embedding.engine.plugins.FlutterPlugin.FlutterPluginBinding
|
||||
import mozilla.components.browser.state.action.SystemAction
|
||||
import mozilla.components.feature.addons.logger
|
||||
import mozilla.components.support.base.log.Log
|
||||
import mozilla.components.support.base.log.sink.AndroidLogSink
|
||||
|
||||
/**
|
||||
* Implementation of GeckoBrowserApi that handles browser-related operations
|
||||
* @param showFragmentCallback Callback function to show native fragment
|
||||
*/
|
||||
class GeckoBrowserApiImpl(private val showFragmentCallback: () -> Boolean) : GeckoBrowserApi {
|
||||
class GeckoBrowserApiImpl : GeckoBrowserApi {
|
||||
companion object {
|
||||
private const val TAG = "GeckoBrowserApiImpl"
|
||||
private const val FRAGMENT_CONTAINER_ID = 0xBEEF
|
||||
|
||||
private var isGeckoInitialized = false
|
||||
}
|
||||
|
||||
private val components by lazy {
|
||||
requireNotNull(GlobalComponents.components) { "Components not initialized" }
|
||||
}
|
||||
|
||||
private var activity: Activity? = null
|
||||
private var isPlatformViewRegistered = false
|
||||
|
||||
private lateinit var _flutterPluginBinding: FlutterPlugin.FlutterPluginBinding
|
||||
private lateinit var _flutterEvents : GeckoStateEvents
|
||||
|
||||
fun attachBinding(flutterPluginBinding: FlutterPluginBinding) {
|
||||
_flutterPluginBinding = flutterPluginBinding
|
||||
_flutterEvents = GeckoStateEvents(_flutterPluginBinding.binaryMessenger)
|
||||
}
|
||||
|
||||
fun attachActivity(activity: Activity) {
|
||||
this.activity = activity
|
||||
|
||||
_flutterPluginBinding.platformViewRegistry.registerViewFactory(
|
||||
"eu.lensai/gecko", GeckoViewFactory(
|
||||
activity,
|
||||
FRAGMENT_CONTAINER_ID,
|
||||
_flutterEvents
|
||||
)
|
||||
)
|
||||
|
||||
isPlatformViewRegistered = true
|
||||
}
|
||||
|
||||
fun detachActivity() {
|
||||
this.activity = null
|
||||
isPlatformViewRegistered = false
|
||||
}
|
||||
|
||||
override fun initialize() {
|
||||
synchronized(this) {
|
||||
if(!isGeckoInitialized) {
|
||||
Log.addSink(AndroidLogSink())
|
||||
|
||||
setupGeckoEngine()
|
||||
isGeckoInitialized = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun showNativeFragment(): Boolean {
|
||||
@@ -24,6 +106,85 @@ class GeckoBrowserApiImpl(private val showFragmentCallback: () -> Boolean) : Gec
|
||||
return false
|
||||
}
|
||||
|
||||
private fun setupGeckoEngine() {
|
||||
val selectionActionEvents = GeckoSelectionActionEvents(_flutterPluginBinding.binaryMessenger)
|
||||
|
||||
val selectionActionDelegate = DefaultSelectionActionDelegate(selectionActionEvents)
|
||||
|
||||
val readerViewController =
|
||||
ReaderViewController(_flutterPluginBinding.binaryMessenger)
|
||||
|
||||
val extensionEvents = BrowserExtensionEvents(_flutterPluginBinding.binaryMessenger)
|
||||
|
||||
val addonEvents = GeckoAddonEvents(_flutterPluginBinding.binaryMessenger)
|
||||
val tabContentEvents = GeckoTabContentEvents(_flutterPluginBinding.binaryMessenger)
|
||||
|
||||
val suggestionEvents = GeckoSuggestionEvents(_flutterPluginBinding.binaryMessenger)
|
||||
GeckoSuggestionApi.setUp(_flutterPluginBinding.binaryMessenger, GeckoSuggestionApiImpl(suggestionEvents))
|
||||
|
||||
GlobalComponents.setUp(
|
||||
_flutterPluginBinding.applicationContext,
|
||||
_flutterEvents,
|
||||
readerViewController,
|
||||
selectionActionDelegate,
|
||||
addonEvents,
|
||||
tabContentEvents,
|
||||
extensionEvents
|
||||
)
|
||||
|
||||
GeckoEngineSettingsApi.setUp(_flutterPluginBinding.binaryMessenger, GeckoEngineSettingsApiImpl())
|
||||
GeckoAddonsApi.setUp(_flutterPluginBinding.binaryMessenger, GeckoAddonsApiImpl(_flutterPluginBinding.applicationContext))
|
||||
GeckoSessionApi.setUp(_flutterPluginBinding.binaryMessenger, GeckoSessionApiImpl())
|
||||
GeckoTabsApi.setUp(_flutterPluginBinding.binaryMessenger, GeckoTabsApiImpl())
|
||||
GeckoIconsApi.setUp(_flutterPluginBinding.binaryMessenger, GeckoIconsApiImpl())
|
||||
GeckoCookieApi.setUp(_flutterPluginBinding.binaryMessenger, GeckoCookieApiImpl())
|
||||
GeckoPrefApi.setUp(_flutterPluginBinding.binaryMessenger, GeckoPrefApiImpl())
|
||||
GeckoContainerProxyApi.setUp(_flutterPluginBinding.binaryMessenger, GeckoContainerProxyApiImpl())
|
||||
GeckoFindApi.setUp(_flutterPluginBinding.binaryMessenger, GeckoFindApiImpl())
|
||||
GeckoSelectionActionController.setUp(_flutterPluginBinding.binaryMessenger, GeckoSelectionActionControllerImpl(
|
||||
selectionActionDelegate
|
||||
))
|
||||
GeckoDeleteBrowsingDataController.setUp(_flutterPluginBinding.binaryMessenger, GeckoDeleteBrowsingDataControllerImpl())
|
||||
GeckoDownloadsApi.setUp(_flutterPluginBinding.binaryMessenger, GeckoDownloadsApiImpl())
|
||||
GeckoBrowserExtensionApi.setUp(_flutterPluginBinding.binaryMessenger, GeckoBrowserExtensionApiImpl())
|
||||
|
||||
ReaderViewEvents.setUp(
|
||||
_flutterPluginBinding.binaryMessenger,
|
||||
components.events.readerViewEvents
|
||||
)
|
||||
|
||||
val intent = Intent(_flutterPluginBinding.applicationContext, NotificationActivity::class.java)
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
_flutterPluginBinding.applicationContext.startActivity(intent)
|
||||
}
|
||||
|
||||
private fun showFragmentCallback(): Boolean {
|
||||
if (!isPlatformViewRegistered) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (activity == null || activity !is FragmentActivity) {
|
||||
return false
|
||||
}
|
||||
|
||||
val fragmentActivity = activity as FragmentActivity
|
||||
|
||||
// Check if the container view exists in the view hierarchy
|
||||
val container = fragmentActivity.findViewById<View>(FRAGMENT_CONTAINER_ID)
|
||||
if (container == null) {
|
||||
// Container doesn't exist yet, retry later
|
||||
return false
|
||||
}
|
||||
|
||||
val nativeFragment = BrowserFragment.create()
|
||||
val fm = fragmentActivity.supportFragmentManager
|
||||
fm.beginTransaction()
|
||||
.replace(FRAGMENT_CONTAINER_ID, nativeFragment)
|
||||
.commitAllowingStateLoss()
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onTrimMemory(level: Long) {
|
||||
requireNotNull(GlobalComponents.components) { "Components not initialized" }
|
||||
|
||||
|
||||
+17
@@ -1,7 +1,10 @@
|
||||
package eu.lensai.flutter_mozilla_components.api
|
||||
|
||||
import eu.lensai.flutter_mozilla_components.feature.BrowserExtensionFeature
|
||||
import eu.lensai.flutter_mozilla_components.feature.ContainerProxyFeature
|
||||
import eu.lensai.flutter_mozilla_components.feature.ResultConsumer
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.GeckoContainerProxyApi
|
||||
import org.json.JSONObject
|
||||
|
||||
class GeckoContainerProxyApiImpl : GeckoContainerProxyApi {
|
||||
override fun setProxyPort(port: Long) {
|
||||
@@ -15,4 +18,18 @@ class GeckoContainerProxyApiImpl : GeckoContainerProxyApi {
|
||||
override fun removeContainerProxy(contextId: String) {
|
||||
ContainerProxyFeature.scheduleRequest("removeContainerProxy", contextId)
|
||||
}
|
||||
|
||||
override fun healthcheck(callback: (Result<Boolean>) -> Unit) {
|
||||
ContainerProxyFeature.scheduleRequestWithResponse("healthcheck", Unit, object :
|
||||
ResultConsumer<JSONObject> {
|
||||
override fun success(result: JSONObject) {
|
||||
val resultStatus = result.getBoolean("result")
|
||||
callback(Result.success(resultStatus))
|
||||
}
|
||||
|
||||
override fun error(errorCode: String, errorMessage: String?, errorDetails: Any?) {
|
||||
callback(Result.failure(Exception("$errorCode $errorMessage $errorDetails")))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
+52
@@ -20,6 +20,10 @@ object ContainerProxyFeature {
|
||||
private const val CONTAINER_PROXY_REPORTER_EXTENSION_URL = "resource://android/assets/extensions/container_proxy/"
|
||||
private const val CONTAINER_PROXY_REPORTER_MESSAGING_ID = "containerProxy"
|
||||
|
||||
private var nextRequestId: Int = 0
|
||||
private val requestHandlers = HashMap<Int, ResultConsumer<JSONObject>>()
|
||||
private val mutex = Mutex()
|
||||
|
||||
@VisibleForTesting
|
||||
// This is an internal var to make it mutable for unit testing purposes only
|
||||
internal var extensionController = WebExtensionController(
|
||||
@@ -40,7 +44,55 @@ object ContainerProxyFeature {
|
||||
}
|
||||
}
|
||||
|
||||
fun scheduleRequestWithResponse(
|
||||
command: String,
|
||||
args: Any,
|
||||
callback: ResultConsumer<JSONObject>
|
||||
) {
|
||||
val message = JSONObject()
|
||||
message.put("action", command);
|
||||
message.put("args", args)
|
||||
|
||||
runBlocking {
|
||||
withContext(Dispatchers.Default) {
|
||||
mutex.withLock {
|
||||
message.put("id", nextRequestId)
|
||||
|
||||
requestHandlers[nextRequestId] = callback
|
||||
|
||||
nextRequestId += 1
|
||||
|
||||
extensionController.sendBackgroundMessage(message)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class ContainerProxyBackgroundMessageHandler() : MessageHandler {
|
||||
override fun onPortMessage(message: Any, port: Port) {
|
||||
runBlocking {
|
||||
withContext(Dispatchers.Default) {
|
||||
mutex.withLock {
|
||||
val messageJSON = message as JSONObject;
|
||||
val type = messageJSON.getString("type")
|
||||
|
||||
if (type == "healthcheck") {
|
||||
val requestId = messageJSON.getInt("id")
|
||||
val status = messageJSON.getString("status")
|
||||
if (status == "success") {
|
||||
requestHandlers[requestId]?.success(message)
|
||||
} else {
|
||||
requestHandlers[requestId]?.error(
|
||||
"Container Proxy",
|
||||
"Failed to perform operation",
|
||||
message.getString("error")
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -50,7 +50,7 @@ class FlutterEventMiddleware(private val flutterEvents: GeckoStateEvents) : Midd
|
||||
) {
|
||||
when (action) {
|
||||
is ContentAction.UpdateThumbnailAction -> {
|
||||
val resized = action.thumbnail.resize(maxWidth = 640, maxHeight = 480);
|
||||
val resized = action.thumbnail.resize(maxWidth = 1280, maxHeight = 800);
|
||||
val bytes = resized.toWebPBytes()
|
||||
|
||||
runOnUiThread {
|
||||
|
||||
+36
@@ -1994,6 +1994,7 @@ private open class GeckoPigeonCodec : StandardMessageCodec() {
|
||||
|
||||
/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
|
||||
interface GeckoBrowserApi {
|
||||
fun initialize()
|
||||
fun showNativeFragment(): Boolean
|
||||
fun onTrimMemory(level: Long)
|
||||
|
||||
@@ -2006,6 +2007,22 @@ interface GeckoBrowserApi {
|
||||
@JvmOverloads
|
||||
fun setUp(binaryMessenger: BinaryMessenger, api: GeckoBrowserApi?, messageChannelSuffix: String = "") {
|
||||
val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else ""
|
||||
run {
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.flutter_mozilla_components.GeckoBrowserApi.initialize$separatedMessageChannelSuffix", codec)
|
||||
if (api != null) {
|
||||
channel.setMessageHandler { _, reply ->
|
||||
val wrapped: List<Any?> = try {
|
||||
api.initialize()
|
||||
listOf(null)
|
||||
} catch (exception: Throwable) {
|
||||
wrapError(exception)
|
||||
}
|
||||
reply.reply(wrapped)
|
||||
}
|
||||
} else {
|
||||
channel.setMessageHandler(null)
|
||||
}
|
||||
}
|
||||
run {
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.flutter_mozilla_components.GeckoBrowserApi.showNativeFragment$separatedMessageChannelSuffix", codec)
|
||||
if (api != null) {
|
||||
@@ -3019,6 +3036,7 @@ interface GeckoContainerProxyApi {
|
||||
fun setProxyPort(port: Long)
|
||||
fun addContainerProxy(contextId: String)
|
||||
fun removeContainerProxy(contextId: String)
|
||||
fun healthcheck(callback: (Result<Boolean>) -> Unit)
|
||||
|
||||
companion object {
|
||||
/** The codec used by GeckoContainerProxyApi. */
|
||||
@@ -3083,6 +3101,24 @@ interface GeckoContainerProxyApi {
|
||||
channel.setMessageHandler(null)
|
||||
}
|
||||
}
|
||||
run {
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.flutter_mozilla_components.GeckoContainerProxyApi.healthcheck$separatedMessageChannelSuffix", codec)
|
||||
if (api != null) {
|
||||
channel.setMessageHandler { _, reply ->
|
||||
api.healthcheck{ result: Result<Boolean> ->
|
||||
val error = result.exceptionOrNull()
|
||||
if (error != null) {
|
||||
reply.reply(wrapError(error))
|
||||
} else {
|
||||
val data = result.getOrNull()
|
||||
reply.reply(wrapResult(data))
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
channel.setMessageHandler(null)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+10
-3
@@ -7,7 +7,8 @@ console.log('Background script started')
|
||||
const store = new Store()
|
||||
|
||||
interface Message {
|
||||
action: 'setProxyPort' | 'addContainerProxy' | 'removeContainerProxy';
|
||||
id: String | undefined;
|
||||
action: 'setProxyPort' | 'addContainerProxy' | 'removeContainerProxy' | 'healthcheck';
|
||||
args: any;
|
||||
}
|
||||
|
||||
@@ -35,8 +36,14 @@ port.onMessage.addListener((raw: unknown): void => {
|
||||
case "removeContainerProxy":
|
||||
store.removeContainerProxyRelation(message.args, "tor")
|
||||
break
|
||||
|
||||
|
||||
case "healthcheck":
|
||||
port.postMessage({
|
||||
"type": "healthcheck",
|
||||
"id": message.id,
|
||||
"status": "success",
|
||||
"result": true
|
||||
});
|
||||
break
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ export 'src/data/models/load_url_flags.dart';
|
||||
export 'src/data/models/source.dart';
|
||||
export 'src/domain/entities/default_selection_actions.dart';
|
||||
export 'src/domain/services/gecko_addon.dart';
|
||||
export 'src/domain/services/gecko_browser.dart';
|
||||
export 'src/domain/services/gecko_browser_extension.dart';
|
||||
export 'src/domain/services/gecko_container_proxy.dart';
|
||||
export 'src/domain/services/gecko_cookie.dart';
|
||||
|
||||
@@ -7,6 +7,10 @@ class GeckoBrowserService {
|
||||
|
||||
GeckoBrowserService({GeckoBrowserApi? api}) : _api = api ?? _apiInstance;
|
||||
|
||||
Future<void> initialize() {
|
||||
return _api.initialize();
|
||||
}
|
||||
|
||||
Future<bool> showNativeFragment() {
|
||||
return _api.showNativeFragment();
|
||||
}
|
||||
|
||||
@@ -14,4 +14,12 @@ class GeckoContainerProxyService {
|
||||
Future<void> removeContainerProxy(String contextId) {
|
||||
return _apiInstance.removeContainerProxy(contextId);
|
||||
}
|
||||
|
||||
Future<bool> healthcheck() {
|
||||
try {
|
||||
return _apiInstance.healthcheck();
|
||||
} catch (_) {
|
||||
return Future.value(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1983,6 +1983,29 @@ class GeckoBrowserApi {
|
||||
|
||||
final String pigeonVar_messageChannelSuffix;
|
||||
|
||||
Future<void> initialize() async {
|
||||
final String pigeonVar_channelName = 'dev.flutter.pigeon.flutter_mozilla_components.GeckoBrowserApi.initialize$pigeonVar_messageChannelSuffix';
|
||||
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>(
|
||||
pigeonVar_channelName,
|
||||
pigeonChannelCodec,
|
||||
binaryMessenger: pigeonVar_binaryMessenger,
|
||||
);
|
||||
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(null);
|
||||
final List<Object?>? pigeonVar_replyList =
|
||||
await pigeonVar_sendFuture as List<Object?>?;
|
||||
if (pigeonVar_replyList == null) {
|
||||
throw _createConnectionError(pigeonVar_channelName);
|
||||
} else if (pigeonVar_replyList.length > 1) {
|
||||
throw PlatformException(
|
||||
code: pigeonVar_replyList[0]! as String,
|
||||
message: pigeonVar_replyList[1] as String?,
|
||||
details: pigeonVar_replyList[2],
|
||||
);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> showNativeFragment() async {
|
||||
final String pigeonVar_channelName = 'dev.flutter.pigeon.flutter_mozilla_components.GeckoBrowserApi.showNativeFragment$pigeonVar_messageChannelSuffix';
|
||||
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>(
|
||||
@@ -3251,6 +3274,34 @@ class GeckoContainerProxyApi {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> healthcheck() async {
|
||||
final String pigeonVar_channelName = 'dev.flutter.pigeon.flutter_mozilla_components.GeckoContainerProxyApi.healthcheck$pigeonVar_messageChannelSuffix';
|
||||
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>(
|
||||
pigeonVar_channelName,
|
||||
pigeonChannelCodec,
|
||||
binaryMessenger: pigeonVar_binaryMessenger,
|
||||
);
|
||||
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(null);
|
||||
final List<Object?>? pigeonVar_replyList =
|
||||
await pigeonVar_sendFuture as List<Object?>?;
|
||||
if (pigeonVar_replyList == null) {
|
||||
throw _createConnectionError(pigeonVar_channelName);
|
||||
} else if (pigeonVar_replyList.length > 1) {
|
||||
throw PlatformException(
|
||||
code: pigeonVar_replyList[0]! as String,
|
||||
message: pigeonVar_replyList[1] as String?,
|
||||
details: pigeonVar_replyList[2],
|
||||
);
|
||||
} else if (pigeonVar_replyList[0] == null) {
|
||||
throw PlatformException(
|
||||
code: 'null-error',
|
||||
message: 'Host platform returned null value for non-null return value.',
|
||||
);
|
||||
} else {
|
||||
return (pigeonVar_replyList[0] as bool?)!;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class GeckoCookieApi {
|
||||
|
||||
@@ -736,6 +736,7 @@ class ShareInternetResourceState {
|
||||
)
|
||||
@HostApi()
|
||||
abstract class GeckoBrowserApi {
|
||||
void initialize();
|
||||
bool showNativeFragment();
|
||||
void onTrimMemory(int level);
|
||||
}
|
||||
@@ -953,6 +954,9 @@ abstract class GeckoContainerProxyApi {
|
||||
void setProxyPort(int port);
|
||||
void addContainerProxy(String contextId);
|
||||
void removeContainerProxy(String contextId);
|
||||
|
||||
@async
|
||||
bool healthcheck();
|
||||
}
|
||||
|
||||
@HostApi()
|
||||
|
||||
Reference in New Issue
Block a user