Commit b97aef4b authored by Christian Sadilek's avatar Christian Sadilek
Browse files

Closes #3639: browser-state: Add onLowMemory behavior

parent bcf9351e
......@@ -8,6 +8,7 @@ import mozilla.components.browser.session.ext.syncDispatch
import mozilla.components.browser.session.ext.toCustomTabSessionState
import mozilla.components.browser.session.ext.toTabSessionState
import mozilla.components.browser.state.action.CustomTabListAction
import mozilla.components.browser.state.action.SystemAction
import mozilla.components.browser.state.action.TabListAction
import mozilla.components.browser.state.store.BrowserStore
import mozilla.components.concept.engine.Engine
......@@ -227,7 +228,10 @@ class SessionManager(
* Informs this [SessionManager] that the OS is in low memory condition so it
* can reduce its allocated objects.
*/
fun onLowMemory() = delegate.onLowMemory()
fun onLowMemory() {
delegate.onLowMemory()
store?.syncDispatch(SystemAction.LowMemoryAction)
}
companion object {
const val NO_SELECTION = -1
......
......@@ -32,7 +32,8 @@ private fun Session.toContentState(): ContentState {
progress,
loading,
searchTerms,
securityInfo.toSecurityInfoState()
securityInfo.toSecurityInfoState(),
thumbnail
)
}
......
......@@ -451,4 +451,31 @@ class SessionManagerMigrationTest {
}
}
}
@Test
fun `thumbnails of all but selected session should be removed on low memory`() {
val store = BrowserStore()
val sessionManager = SessionManager(engine = mock(), store = store)
val session1 = Session("https://www.mozilla.org")
val session2 = Session("https://getpocket.com")
val session3 = Session("https://www.firefox.com")
sessionManager.add(session1, false)
session1.thumbnail = mock()
sessionManager.add(session2, false)
session2.thumbnail = mock()
sessionManager.add(session3, true)
session3.thumbnail = mock()
val allSessionsMustHaveAThumbnail = store.state.tabs.all { it.content.thumbnail != null }
assertTrue(allSessionsMustHaveAThumbnail)
sessionManager.onLowMemory()
assertNull(store.state.tabs[0].content.thumbnail)
assertNull(store.state.tabs[1].content.thumbnail)
// Thumbnail of selected session should not have been removed
assertNotNull(store.state.tabs[2].content.thumbnail)
}
}
......@@ -668,7 +668,7 @@ class SessionManagerTest {
}
@Test
fun `all not selected sessions should be removed on Low Memory`() {
fun `thumbnails of all but selected session should be removed on low memory`() {
val manager = SessionManager(mock())
val emptyBitmap = spy(Bitmap::class.java)
......
......@@ -18,6 +18,17 @@ import mozilla.components.lib.state.Action
*/
sealed class BrowserAction : Action
/**
* [BrowserAction] implementations to react to system events.
*/
sealed class SystemAction : BrowserAction() {
/**
* Optimizes the [BrowserState] by removing unneeded and optional
* resources if the system is in a low memory condition.
*/
object LowMemoryAction : SystemAction()
}
/**
* [BrowserAction] implementations related to updating the list of [TabSessionState] inside [BrowserState].
*/
......
......@@ -7,6 +7,7 @@ package mozilla.components.browser.state.reducer
import mozilla.components.browser.state.action.BrowserAction
import mozilla.components.browser.state.action.ContentAction
import mozilla.components.browser.state.action.CustomTabListAction
import mozilla.components.browser.state.action.SystemAction
import mozilla.components.browser.state.action.TabListAction
import mozilla.components.browser.state.state.BrowserState
import mozilla.components.browser.state.store.BrowserStore
......@@ -21,9 +22,10 @@ import mozilla.components.lib.state.Action
internal object BrowserStateReducer {
fun reduce(state: BrowserState, action: BrowserAction): BrowserState {
return when (action) {
is TabListAction -> TabListReducer.reduce(state, action)
is CustomTabListAction -> CustomTabListReducer.reduce(state, action)
is ContentAction -> ContentStateReducer.reduce(state, action)
is CustomTabListAction -> CustomTabListReducer.reduce(state, action)
is SystemAction -> SystemReducer.reduce(state, action)
is TabListAction -> TabListReducer.reduce(state, action)
}
}
}
/* 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.state.reducer
import mozilla.components.browser.state.action.SystemAction
import mozilla.components.browser.state.state.BrowserState
internal object SystemReducer {
/**
* [SystemAction] Reducer function for modifying [BrowserState].
*/
fun reduce(state: BrowserState, action: SystemAction): BrowserState {
return when (action) {
is SystemAction.LowMemoryAction -> {
val updatedTabs = state.tabs.map {
if (state.selectedTabId != it.id) {
it.copy(content = it.content.copy(thumbnail = null))
} else {
it
}
}
state.copy(tabs = updatedTabs)
}
}
}
}
/* 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.state.action
import mozilla.components.browser.state.state.BrowserState
import mozilla.components.browser.state.state.createTab
import mozilla.components.browser.state.store.BrowserStore
import mozilla.components.support.test.ext.joinBlocking
import mozilla.components.support.test.mock
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertNull
import org.junit.Test
class SystemActionTest {
@Test
fun `LowMemoryAction removes thumbnails`() {
val initialState = BrowserState(tabs = listOf(
createTab(url = "https://www.mozilla.org", id = "0"),
createTab(url = "https://www.firefox.com", id = "1"),
createTab(url = "https://www.firefox.com", id = "2")
))
val store = BrowserStore(initialState)
store.dispatch(ContentAction.UpdateThumbnailAction("0", mock())).joinBlocking()
store.dispatch(ContentAction.UpdateThumbnailAction("1", mock())).joinBlocking()
store.dispatch(ContentAction.UpdateThumbnailAction("2", mock())).joinBlocking()
store.dispatch(TabListAction.SelectTabAction(tabId = "2")).joinBlocking()
assertNotNull(store.state.tabs[0].content.thumbnail)
assertNotNull(store.state.tabs[1].content.thumbnail)
assertNotNull(store.state.tabs[2].content.thumbnail)
store.dispatch(SystemAction.LowMemoryAction).joinBlocking()
assertNull(store.state.tabs[0].content.thumbnail)
assertNull(store.state.tabs[1].content.thumbnail)
// Thumbnail of selected tab should not have been removed
assertNotNull(store.state.tabs[2].content.thumbnail)
}
}
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