Skip to content

Commit 860372e

Browse files
MozLandocsadilek
andcommitted
5327: Issue mozilla-mobile#4500: Wire up AddonManager -> Engine r=Amejia481,psymoon a=csadilek Next 🧩. Wiring Up AddonManager and Engine. Next step after that: Wiring up UI and AddonManager. Co-authored-by: Christian Sadilek <[email protected]>
2 parents b313694 + ed8ab64 commit 860372e

File tree

8 files changed

+438
-14
lines changed

8 files changed

+438
-14
lines changed

components/browser/engine-gecko-beta/src/main/java/mozilla/components/browser/engine/gecko/webextension/GeckoWebExtension.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@ class GeckoWebExtension(
222222

223223
// Not yet supported
224224
override fun getMetadata(): Metadata? = null
225+
override fun isEnabled(): Boolean = true
225226
}
226227

227228
/**

components/browser/engine-gecko-nightly/src/main/java/mozilla/components/browser/engine/gecko/webextension/GeckoWebExtension.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,11 @@ class GeckoWebExtension(
242242
)
243243
}
244244
}
245+
246+
override fun isEnabled(): Boolean {
247+
// TODO https://bugzilla.mozilla.org/show_bug.cgi?id=1599585
248+
return true
249+
}
245250
}
246251

247252
/**

components/browser/engine-gecko-nightly/src/test/java/mozilla/components/browser/engine/gecko/webextension/GeckoWebExtensionTest.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,4 +362,10 @@ class GeckoWebExtensionTest {
362362
val externalExtension = GeckoWebExtension(WebExtension("https://url", "id", WebExtension.Flags.NONE))
363363
assertFalse(externalExtension.isBuiltIn())
364364
}
365+
366+
@Test
367+
fun `isEnabled depends on native state`() {
368+
val extension = GeckoWebExtension(WebExtension("resource://url", "id", WebExtension.Flags.NONE))
369+
assertTrue(extension.isEnabled())
370+
}
365371
}

components/browser/engine-gecko/src/main/java/mozilla/components/browser/engine/gecko/webextension/GeckoWebExtension.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ class GeckoWebExtension(
151151
override fun registerActionHandler(session: EngineSession, actionHandler: ActionHandler) = Unit
152152
override fun hasActionHandler(session: EngineSession) = false
153153
override fun getMetadata(): Metadata? = null
154+
override fun isEnabled(): Boolean = true
154155
}
155156

156157
/**

components/concept/engine/src/main/java/mozilla/components/concept/engine/webextension/WebExtension.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import org.json.JSONObject
1818
* @property supportActions whether or not browser and page actions are handled when
1919
* received from the web extension
2020
*/
21+
@Suppress("TooManyFunctions")
2122
abstract class WebExtension(
2223
val id: String,
2324
val url: String,
@@ -127,6 +128,11 @@ abstract class WebExtension(
127128
* APK file) or coming from an external source.
128129
*/
129130
fun isBuiltIn(): Boolean = Uri.parse(url).scheme == "resource"
131+
132+
/**
133+
* Checks whether or not this extension is enabled.
134+
*/
135+
abstract fun isEnabled(): Boolean
130136
}
131137

132138
/**

components/feature/addons/src/main/java/mozilla/components/feature/addons/AddonManager.kt

Lines changed: 125 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,24 @@
44

55
package mozilla.components.feature.addons
66

7-
import mozilla.components.browser.state.action.WebExtensionAction
8-
import mozilla.components.browser.state.state.WebExtensionState
97
import mozilla.components.browser.state.store.BrowserStore
108
import mozilla.components.concept.engine.Engine
119
import mozilla.components.concept.engine.webextension.WebExtension
1210
import mozilla.components.feature.addons.update.AddonUpdater
1311
import mozilla.components.feature.addons.update.AddonUpdater.Status
1412
import mozilla.components.feature.addons.update.GlobalAddonManagerProvider
1513
import mozilla.components.support.webextensions.WebExtensionSupport
14+
import mozilla.components.support.webextensions.WebExtensionSupport.installedExtensions
15+
import java.lang.IllegalStateException
1616

1717
/**
1818
* Provides access to installed and recommended [Addon]s and manages their states.
1919
*
2020
* @property store The application's [BrowserStore].
21+
* @property engine The application's browser [Engine].
2122
* @property addonsProvider The [AddonsProvider] to query available [Addon]s.
23+
* @property addonUpdater The [AddonUpdater] instance to use when checking / triggering
24+
* updates.
2225
*/
2326
class AddonManager(
2427
private val store: BrowserStore,
@@ -45,28 +48,131 @@ class AddonManager(
4548
// Make sure extension support is initialized, i.e. the state of all installed extensions is known.
4649
WebExtensionSupport.awaitInitialization()
4750

48-
// TODO for testing purposes -> remove once management API lands
49-
val ublockId = "607454"
50-
store.dispatch(WebExtensionAction.InstallWebExtensionAction(WebExtensionState(ublockId))).join()
51-
5251
return addonsProvider.getAvailableAddons().map { addon ->
53-
store.state.extensions[addon.id]?.let { installedAddon ->
54-
// TODO Add fields once we get the management API:
55-
// https://github.com/mozilla-mobile/android-components/issues/4500
56-
addon.copy(installedState = Addon.InstalledState(installedAddon.id, "1.0", "https://mozilla.org"))
57-
} ?: addon
52+
installedExtensions[addon.id]?.let { addon.copy(installedState = it.toInstalledState()) } ?: addon
5853
}
5954
} catch (throwable: Throwable) {
6055
throw AddonManagerException(throwable)
6156
}
6257
}
6358

6459
/**
65-
* Try updates the addon with the provided [id] by updating it in the the [store] and re-attaching
66-
* all the handlers. If there is no update available nothing will happen.
60+
* Installs the provided [Addon].
61+
*
62+
* @param addon the addon to install.
63+
* @param onSuccess (optional) callback invoked if the addon was installed successfully,
64+
* providing access to the [Addon] object.
65+
* @param onError (optional) callback invoked if there was an error installing the addon.
66+
*/
67+
fun installAddon(
68+
addon: Addon,
69+
onSuccess: ((Addon) -> Unit) = { },
70+
onError: ((String, Throwable) -> Unit) = { _, _ -> }
71+
) {
72+
engine.installWebExtension(
73+
id = addon.id,
74+
url = addon.downloadUrl,
75+
onSuccess = { ext ->
76+
val installedAddon = addon.copy(installedState = ext.toInstalledState())
77+
addonUpdater.registerForFutureUpdates(installedAddon.id)
78+
onSuccess(installedAddon)
79+
},
80+
onError = onError
81+
)
82+
}
83+
84+
/**
85+
* Uninstalls the provided [Addon].
86+
*
87+
* @param addon the addon to uninstall.
88+
* @param onSuccess (optional) callback invoked if the addon was uninstalled successfully.
89+
* @param onError (optional) callback invoked if there was an error installing the addon.
90+
*/
91+
fun uninstallAddon(
92+
addon: Addon,
93+
onSuccess: (() -> Unit) = { },
94+
onError: ((String, Throwable) -> Unit) = { _, _ -> }
95+
) {
96+
val extension = addon.installedState?.let { installedExtensions[it.id] }
97+
if (extension == null) {
98+
onError(addon.id, IllegalStateException("Addon is not installed"))
99+
return
100+
}
101+
102+
engine.uninstallWebExtension(
103+
extension,
104+
onSuccess = {
105+
addonUpdater.unregisterForFutureUpdates(addon.id)
106+
onSuccess()
107+
},
108+
onError = onError
109+
)
110+
}
111+
112+
/**
113+
* Enables the provided [Addon].
114+
*
115+
* @param addon the [Addon] to enable.
116+
* @param onSuccess (optional) callback invoked with the enabled [Addon].
117+
* @param onError (optional) callback invoked if there was an error enabling
118+
*/
119+
fun enableAddon(
120+
addon: Addon,
121+
onSuccess: ((Addon) -> Unit) = { },
122+
onError: ((Throwable) -> Unit) = { }
123+
) {
124+
val extension = addon.installedState?.let { installedExtensions[it.id] }
125+
if (extension == null) {
126+
onError(IllegalStateException("Addon is not installed"))
127+
return
128+
}
129+
130+
engine.enableWebExtension(
131+
extension,
132+
onSuccess = { ext ->
133+
val enabledAddon = addon.copy(installedState = ext.toInstalledState())
134+
onSuccess(enabledAddon)
135+
},
136+
onError = onError
137+
)
138+
}
139+
140+
/**
141+
* Disables the provided [Addon].
142+
*
143+
* @param addon the [Addon] to disable.
144+
* @param onSuccess (optional) callback invoked with the enabled [Addon].
145+
* @param onError (optional) callback invoked if there was an error enabling
146+
*/
147+
fun disableAddon(
148+
addon: Addon,
149+
onSuccess: ((Addon) -> Unit) = { },
150+
onError: ((Throwable) -> Unit) = { }
151+
) {
152+
val extension = addon.installedState?.let { installedExtensions[it.id] }
153+
if (extension == null) {
154+
onError(IllegalStateException("Addon is not installed"))
155+
return
156+
}
157+
158+
engine.disableWebExtension(
159+
extension,
160+
onSuccess = { ext ->
161+
val disabledAddon = addon.copy(installedState = ext.toInstalledState())
162+
onSuccess(disabledAddon)
163+
},
164+
onError = onError
165+
)
166+
}
167+
168+
/**
169+
* Updates the addon with the provided [id] if an update is available.
170+
*
171+
* @param id the ID of the addon
172+
* @param onFinish callback invoked with the [Status] of the update once complete.
67173
*/
68174
fun updateAddon(id: String, onFinish: ((Status) -> Unit)) {
69-
val extension = WebExtensionSupport.installedExtensions[id]
175+
val extension = installedExtensions[id]
70176

71177
if (extension == null) {
72178
onFinish(Status.NotInstalled)
@@ -95,3 +201,8 @@ class AddonManager(
95201
* Wraps exceptions thrown by either the initialization process or an [AddonsProvider].
96202
*/
97203
class AddonManagerException(throwable: Throwable) : Exception(throwable)
204+
205+
private fun WebExtension.toInstalledState() =
206+
// TODO Add optionsUrl
207+
// TODO https://bugzilla.mozilla.org/show_bug.cgi?id=1598792
208+
Addon.InstalledState(id, getMetadata()?.version ?: "", "https://mozilla.org", isEnabled())

0 commit comments

Comments
 (0)