Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(webview): optional unload on pause #5051

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ class SettingsPresenterImpl @Inject constructor(
"crash_reporting" -> prefsRepository.isCrashReporting()
"autoplay_video" -> prefsRepository.isAutoPlayVideoEnabled()
"always_show_first_view_on_app_start" -> prefsRepository.isAlwaysShowFirstViewOnAppStartEnabled()
"unload_when_backgrounded" -> prefsRepository.isUnloadWhenBackgroundedEnabled()
"assist_voice_command_intent" -> {
val componentSetting = view.getPackageManager()?.getComponentEnabledSetting(voiceCommandAppComponent)
componentSetting != null && componentSetting != PackageManager.COMPONENT_ENABLED_STATE_DISABLED
Expand All @@ -95,6 +96,7 @@ class SettingsPresenterImpl @Inject constructor(
"crash_reporting" -> prefsRepository.setCrashReporting(value)
"autoplay_video" -> prefsRepository.setAutoPlayVideo(value)
"always_show_first_view_on_app_start" -> prefsRepository.setAlwaysShowFirstViewOnAppStart(value)
"unload_when_backgrounded" -> prefsRepository.setUnloadWhenBackgroundedEnabled(value)
"assist_voice_command_intent" ->
view.getPackageManager()?.setComponentEnabledSetting(
voiceCommandAppComponent,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -887,7 +887,10 @@ class WebViewActivity : BaseActivity(), io.homeassistant.companion.android.webvi

override fun onResume() {
super.onResume()
if (currentAutoplay != presenter.isAutoPlayVideoEnabled()) {

if (presenter.isUnloadWhenBackgroundedEnabled()) {
restoreView()
} else if (currentAutoplay != presenter.isAutoPlayVideoEnabled()) {
recreate()
}

Expand Down Expand Up @@ -932,7 +935,12 @@ class WebViewActivity : BaseActivity(), io.homeassistant.companion.android.webvi
override fun onPause() {
super.onPause()
presenter.setAppActive(false)
if (!isFinishing && !isRelaunching) SensorReceiver.updateAllSensors(this)
if (!isFinishing && !isRelaunching) {
if (presenter.isUnloadWhenBackgroundedEnabled()) {
unloadView()
}
SensorReceiver.updateAllSensors(this)
}
}

private suspend fun checkAndWarnForDisabledLocation() {
Expand Down Expand Up @@ -1088,6 +1096,36 @@ class WebViewActivity : BaseActivity(), io.homeassistant.companion.android.webvi
exoPlayerView.requestLayout()
}

/**
* Unload the view to stop video feeds and data usage.
*/
private fun unloadView() {
if (webView.url == null) return
if (webView.url !== "about:blank") {
Log.d(TAG, "unloadView: the URL was ${webView.url} before unload, 'about:blank' the WebView to unload")
webView.loadUrl("about:blank")
} else {
Log.d(TAG, "unloadView: the URL is already unloaded")
}
}

/**
* Reload the view to restore previous suspended state.
*/
private fun restoreView() {
if (webView.url == "about:blank") {
Log.d(TAG, "restoreView: the URL was previously unloaded")
if (webView.canGoBack()) {
webView.goBack()
Log.d(TAG, "restoreView: the WebView went back to ${webView.url}")
} else {
Log.w(TAG, "restoreView: the WebView cannot go back")
}
} else {
Log.d(TAG, "restoreView: the URL was not 'about:blank', no need to restore")
}
}

fun processHaptic(hapticType: String) {
val vm = getSystemService<Vibrator>()

Expand Down Expand Up @@ -1136,6 +1174,7 @@ class WebViewActivity : BaseActivity(), io.homeassistant.companion.android.webvi
}
}
}

private fun authenticationResult(result: Int) {
when (result) {
Authenticator.SUCCESS -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ interface WebViewPresenter {
fun isLockEnabled(): Boolean
fun isAutoPlayVideoEnabled(): Boolean
fun isAlwaysShowFirstViewOnAppStartEnabled(): Boolean
fun isUnloadWhenBackgroundedEnabled(): Boolean

fun sessionTimeOut(): Int

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,10 @@ class WebViewPresenterImpl @Inject constructor(
prefsRepository.isAlwaysShowFirstViewOnAppStartEnabled()
}

override fun isUnloadWhenBackgroundedEnabled(): Boolean = runBlocking {
prefsRepository.isUnloadWhenBackgroundedEnabled()
}

override fun onExternalBusMessage(message: JSONObject) {
mainScope.launch {
externalBusRepository.received(message)
Expand Down
5 changes: 5 additions & 0 deletions app/src/main/res/xml/preferences.xml
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,11 @@
android:icon="@drawable/ic_home_variant_outline"
android:title="@string/always_show_first_view_on_app_start"
android:summary="@string/always_show_first_view_on_app_start_summary" />
<SwitchPreference
android:key="unload_when_backgrounded"
android:icon="@drawable/ic_visibility_off"
android:title="@string/unload_when_backgrounded"
android:summary="@string/unload_when_backgrounded_summary" />
<Preference
android:key="nfc_tags"
android:icon="@drawable/ic_nfc"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ interface PrefsRepository {

suspend fun isAlwaysShowFirstViewOnAppStartEnabled(): Boolean

suspend fun isUnloadWhenBackgroundedEnabled(): Boolean

suspend fun setUnloadWhenBackgroundedEnabled(enabled: Boolean)

suspend fun setAlwaysShowFirstViewOnAppStart(enabled: Boolean)

suspend fun isWebViewDebugEnabled(): Boolean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class PrefsRepositoryImpl @Inject constructor(

companion object {
private const val MIGRATION_PREF = "migration"
private const val MIGRATION_VERSION = 1
private const val MIGRATION_VERSION = 2

private const val PREF_VER = "version"
private const val PREF_THEME = "theme"
Expand All @@ -30,6 +30,7 @@ class PrefsRepositoryImpl @Inject constructor(
private const val PREF_PINCH_TO_ZOOM_ENABLED = "pinch_to_zoom_enabled"
private const val PREF_AUTOPLAY_VIDEO = "autoplay_video"
private const val PREF_ALWAYS_SHOW_FIRST_VIEW_ON_APP_START = "always_show_first_view_on_app_start"
private const val PREF_UNLOAD_WHEN_BACKGROUNDED = "unload_when_backgrounded"
private const val PREF_WEBVIEW_DEBUG_ENABLED = "webview_debug_enabled"
private const val PREF_KEY_ALIAS = "key-alias"
private const val PREF_CRASH_REPORTING_DISABLED = "crash_reporting"
Expand All @@ -42,7 +43,7 @@ class PrefsRepositoryImpl @Inject constructor(
init {
runBlocking {
val currentVersion = localStorage.getInt(MIGRATION_PREF)
if (currentVersion == null || currentVersion < 1) {
if (currentVersion == null || currentVersion < MIGRATION_VERSION) {
integrationStorage.getString(PREF_CONTROLS_AUTH_REQUIRED)?.let {
localStorage.putString(PREF_CONTROLS_AUTH_REQUIRED, it)
}
Expand All @@ -64,6 +65,11 @@ class PrefsRepositoryImpl @Inject constructor(
integrationStorage.getBooleanOrNull(PREF_ALWAYS_SHOW_FIRST_VIEW_ON_APP_START)?.let {
localStorage.putBoolean(PREF_ALWAYS_SHOW_FIRST_VIEW_ON_APP_START, it)
}
integrationStorage.getBooleanOrNull(PREF_UNLOAD_WHEN_BACKGROUNDED)?.let { pref ->
localStorage.putBoolean(PREF_UNLOAD_WHEN_BACKGROUNDED, pref)
} ?: run {
localStorage.putBoolean(PREF_UNLOAD_WHEN_BACKGROUNDED, false)
}
integrationStorage.getBooleanOrNull(PREF_WEBVIEW_DEBUG_ENABLED)?.let {
localStorage.putBoolean(PREF_WEBVIEW_DEBUG_ENABLED, it)
}
Expand Down Expand Up @@ -193,6 +199,14 @@ class PrefsRepositoryImpl @Inject constructor(
return localStorage.getBoolean(PREF_ALWAYS_SHOW_FIRST_VIEW_ON_APP_START)
}

override suspend fun isUnloadWhenBackgroundedEnabled(): Boolean {
return localStorage.getBoolean(PREF_UNLOAD_WHEN_BACKGROUNDED)
}

override suspend fun setUnloadWhenBackgroundedEnabled(enabled: Boolean) {
localStorage.putBoolean(PREF_UNLOAD_WHEN_BACKGROUNDED, enabled)
}

override suspend fun setAlwaysShowFirstViewOnAppStart(enabled: Boolean) {
localStorage.putBoolean(PREF_ALWAYS_SHOW_FIRST_VIEW_ON_APP_START, enabled)
}
Expand Down
2 changes: 2 additions & 0 deletions common/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
<string name="allow">Allow</string>
<string name="always_show_first_view_on_app_start">Always show first view when opening app</string>
<string name="always_show_first_view_on_app_start_summary">The first view of the default dashboard is shown as soon as the app is opened</string>
<string name="unload_when_backgrounded">Unload when the app is paused</string>
<string name="unload_when_backgrounded_summary">Unload any dashboard when the app is not in focus to prevent resource usage in the background (camera streams, etc.).</string>
<string name="app_name">Home Assistant</string>
<string name="app_version_info">App version info</string>
<string name="application_version">Application version</string>
Expand Down