mirror of
https://github.com/home-assistant/android
synced 2024-10-15 12:32:54 +00:00
Multiserver app lock (#3376)
* WebView check app lock on server change * Settings check app lock on server details - If the currently active server has a lock, show it - If the currently visible server has a lock, also show it
This commit is contained in:
parent
c066e7c3cf
commit
0c4c32e512
|
@ -24,6 +24,7 @@ import io.homeassistant.companion.android.common.data.servers.ServerManager
|
|||
import io.homeassistant.companion.android.settings.notification.NotificationHistoryFragment
|
||||
import io.homeassistant.companion.android.settings.qs.ManageTilesFragment
|
||||
import io.homeassistant.companion.android.settings.sensor.SensorDetailFragment
|
||||
import io.homeassistant.companion.android.settings.server.ServerSettingsFragment
|
||||
import io.homeassistant.companion.android.settings.websocket.WebsocketSettingFragment
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import javax.inject.Inject
|
||||
|
@ -113,48 +114,28 @@ class SettingsActivity : BaseActivity() {
|
|||
|
||||
override fun onUserLeaveHint() {
|
||||
super.onUserLeaveHint()
|
||||
runBlocking {
|
||||
if (serverManager.isRegistered()) serverManager.integrationRepository().setAppActive(false)
|
||||
}
|
||||
setAppActive(false)
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
runBlocking {
|
||||
if (serverManager.isRegistered()) serverManager.integrationRepository().setAppActive(false)
|
||||
}
|
||||
setAppActive(false)
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
|
||||
val appLocked = runBlocking {
|
||||
if (serverManager.isRegistered()) serverManager.integrationRepository().isAppLocked()
|
||||
else false
|
||||
}
|
||||
|
||||
blurView.setBlurEnabled(appLocked)
|
||||
blurView.setBlurEnabled(isAppLocked())
|
||||
}
|
||||
|
||||
override fun onWindowFocusChanged(hasFocus: Boolean) {
|
||||
super.onWindowFocusChanged(hasFocus)
|
||||
if (hasFocus && !isFinishing) {
|
||||
val appLocked = runBlocking {
|
||||
if (serverManager.isRegistered()) {
|
||||
try {
|
||||
serverManager.integrationRepository().isAppLocked()
|
||||
} catch (e: IllegalArgumentException) {
|
||||
Log.w(TAG, "Cannot determine app locked state")
|
||||
false
|
||||
}
|
||||
} else false
|
||||
}
|
||||
|
||||
if (appLocked) {
|
||||
if (isAppLocked()) {
|
||||
authenticating = true
|
||||
authenticator.authenticate(getString(commonR.string.biometric_title))
|
||||
blurView.setBlurEnabled(true)
|
||||
} else {
|
||||
setAppActive(true)
|
||||
blurView.setBlurEnabled(false)
|
||||
}
|
||||
}
|
||||
|
@ -176,9 +157,7 @@ class SettingsActivity : BaseActivity() {
|
|||
Authenticator.SUCCESS -> {
|
||||
Log.d(TAG, "Authentication successful, unlocking app")
|
||||
blurView.setBlurEnabled(false)
|
||||
runBlocking {
|
||||
if (serverManager.isRegistered()) serverManager.integrationRepository().setAppActive(true)
|
||||
}
|
||||
setAppActive(true)
|
||||
}
|
||||
Authenticator.CANCELED -> {
|
||||
Log.d(TAG, "Authentication canceled by user, closing activity")
|
||||
|
@ -189,6 +168,42 @@ class SettingsActivity : BaseActivity() {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return `true` if the app is locked for the active server or the currently visible server
|
||||
*/
|
||||
private fun isAppLocked(): Boolean {
|
||||
val serverFragment = supportFragmentManager.findFragmentByTag(ServerSettingsFragment.TAG)
|
||||
val serverLocked = serverFragment?.let { isAppLocked((it as ServerSettingsFragment).getServerId()) } ?: false
|
||||
return serverLocked || isAppLocked(ServerManager.SERVER_ID_ACTIVE)
|
||||
}
|
||||
|
||||
fun isAppLocked(serverId: Int?): Boolean = runBlocking {
|
||||
serverManager.getServer(serverId ?: ServerManager.SERVER_ID_ACTIVE)?.let {
|
||||
try {
|
||||
serverManager.integrationRepository(it.id).isAppLocked()
|
||||
} catch (e: IllegalArgumentException) {
|
||||
Log.w(TAG, "Cannot determine app locked state")
|
||||
false
|
||||
}
|
||||
} ?: false
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the app active for the currently active server, and the currently visible server if
|
||||
* different
|
||||
*/
|
||||
private fun setAppActive(active: Boolean) {
|
||||
val serverFragment = supportFragmentManager.findFragmentByTag(ServerSettingsFragment.TAG)
|
||||
serverFragment?.let { setAppActive((it as ServerSettingsFragment).getServerId(), active) }
|
||||
setAppActive(ServerManager.SERVER_ID_ACTIVE, active)
|
||||
}
|
||||
|
||||
fun setAppActive(serverId: Int?, active: Boolean) = runBlocking {
|
||||
serverManager.getServer(serverId ?: ServerManager.SERVER_ID_ACTIVE)?.let {
|
||||
serverManager.integrationRepository(it.id).setAppActive(active)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
android.R.id.home -> {
|
||||
|
|
|
@ -27,6 +27,7 @@ import androidx.preference.SwitchPreference
|
|||
import com.google.android.material.snackbar.Snackbar
|
||||
import io.homeassistant.companion.android.BuildConfig
|
||||
import io.homeassistant.companion.android.R
|
||||
import io.homeassistant.companion.android.authenticator.Authenticator
|
||||
import io.homeassistant.companion.android.database.server.Server
|
||||
import io.homeassistant.companion.android.nfc.NfcSetupActivity
|
||||
import io.homeassistant.companion.android.onboarding.OnboardApp
|
||||
|
@ -73,6 +74,7 @@ class SettingsFragment(
|
|||
|
||||
private val requestOnboardingResult = registerForActivityResult(OnboardApp(), this::onOnboardingComplete)
|
||||
|
||||
private var serverAuth: Int? = null
|
||||
private val serverMutex = Mutex()
|
||||
|
||||
private var snackbar: Snackbar? = null
|
||||
|
@ -366,13 +368,16 @@ class SettingsFragment(
|
|||
Log.e(TAG, "Unable to set the server icon", e)
|
||||
}
|
||||
serverPreference.setOnPreferenceClickListener {
|
||||
parentFragmentManager.commit {
|
||||
replace(
|
||||
R.id.content,
|
||||
ServerSettingsFragment::class.java,
|
||||
Bundle().apply { putInt(ServerSettingsFragment.EXTRA_SERVER, server.id) }
|
||||
)
|
||||
addToBackStack(getString(commonR.string.server_settings))
|
||||
serverAuth = server.id
|
||||
val settingsActivity = requireActivity() as SettingsActivity
|
||||
val needsAuth = settingsActivity.isAppLocked(server.id)
|
||||
if (!needsAuth) {
|
||||
onServerLockResult(Authenticator.SUCCESS)
|
||||
} else {
|
||||
val canAuth = settingsActivity.requestAuthentication(getString(commonR.string.biometric_set_title), ::onServerLockResult)
|
||||
if (!canAuth) {
|
||||
onServerLockResult(Authenticator.SUCCESS)
|
||||
}
|
||||
}
|
||||
return@setOnPreferenceClickListener true
|
||||
}
|
||||
|
@ -397,6 +402,22 @@ class SettingsFragment(
|
|||
}
|
||||
}
|
||||
|
||||
private fun onServerLockResult(result: Int): Boolean {
|
||||
if (result == Authenticator.SUCCESS && serverAuth != null) {
|
||||
(activity as? SettingsActivity)?.setAppActive(serverAuth, true)
|
||||
parentFragmentManager.commit {
|
||||
replace(
|
||||
R.id.content,
|
||||
ServerSettingsFragment::class.java,
|
||||
Bundle().apply { putInt(ServerSettingsFragment.EXTRA_SERVER, serverAuth!!) },
|
||||
ServerSettingsFragment.TAG
|
||||
)
|
||||
addToBackStack(getString(commonR.string.server_settings))
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private fun onOnboardingComplete(result: OnboardApp.Output?) {
|
||||
lifecycleScope.launch {
|
||||
presenter.addServer(result)
|
||||
|
|
|
@ -42,7 +42,7 @@ import io.homeassistant.companion.android.common.R as commonR
|
|||
class ServerSettingsFragment : ServerSettingsView, PreferenceFragmentCompat() {
|
||||
|
||||
companion object {
|
||||
private const val TAG = "ServerSettingsFragment"
|
||||
const val TAG = "ServerSettingsFragment"
|
||||
|
||||
const val EXTRA_SERVER = "server"
|
||||
}
|
||||
|
@ -305,7 +305,7 @@ class ServerSettingsFragment : ServerSettingsView, PreferenceFragmentCompat() {
|
|||
switchLock?.isChecked = success
|
||||
|
||||
// Prevent requesting authentication after just enabling the app lock
|
||||
presenter.setAppActive()
|
||||
presenter.setAppActive(true)
|
||||
|
||||
findPreference<SwitchPreference>("app_lock_home_bypass")?.isVisible = success
|
||||
findPreference<EditTextPreference>("session_timeout")?.isVisible = success
|
||||
|
@ -385,4 +385,6 @@ class ServerSettingsFragment : ServerSettingsView, PreferenceFragmentCompat() {
|
|||
presenter.onFinish()
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
fun getServerId(): Int = serverId
|
||||
}
|
||||
|
|
|
@ -14,5 +14,5 @@ interface ServerSettingsPresenter {
|
|||
fun isSsidUsed(): Boolean
|
||||
fun clearSsids()
|
||||
|
||||
fun setAppActive()
|
||||
fun setAppActive(active: Boolean)
|
||||
}
|
||||
|
|
|
@ -119,6 +119,9 @@ class ServerSettingsPresenterImpl @Inject constructor(
|
|||
}
|
||||
|
||||
override fun onFinish() {
|
||||
if (serverManager.getServer()?.id != serverId) {
|
||||
setAppActive(false)
|
||||
}
|
||||
mainScope.cancel()
|
||||
}
|
||||
|
||||
|
@ -174,7 +177,7 @@ class ServerSettingsPresenterImpl @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
override fun setAppActive() = runBlocking {
|
||||
serverManager.integrationRepository(serverId).setAppActive(true)
|
||||
override fun setAppActive(active: Boolean) = runBlocking {
|
||||
serverManager.integrationRepository(serverId).setAppActive(active)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,5 +18,7 @@ interface WebView {
|
|||
|
||||
fun relaunchApp()
|
||||
|
||||
fun unlockAppIfNeeded()
|
||||
|
||||
fun showError(errorType: ErrorType = ErrorType.TIMEOUT, error: SslError? = null, description: String? = null)
|
||||
}
|
||||
|
|
|
@ -1022,14 +1022,7 @@ class WebViewActivity : BaseActivity(), io.homeassistant.companion.android.webvi
|
|||
override fun onWindowFocusChanged(hasFocus: Boolean) {
|
||||
super.onWindowFocusChanged(hasFocus)
|
||||
if (hasFocus && !isFinishing) {
|
||||
appLocked = presenter.isAppLocked()
|
||||
if (appLocked) {
|
||||
binding.blurView.setBlurEnabled(true)
|
||||
authenticator.authenticate(getString(commonR.string.biometric_title))
|
||||
} else {
|
||||
binding.blurView.setBlurEnabled(false)
|
||||
}
|
||||
|
||||
unlockAppIfNeeded()
|
||||
val path = intent.getStringExtra(EXTRA_PATH)
|
||||
presenter.onViewReady(path)
|
||||
if (path?.startsWith("entityId:") == true)
|
||||
|
@ -1043,6 +1036,16 @@ class WebViewActivity : BaseActivity(), io.homeassistant.companion.android.webvi
|
|||
}
|
||||
}
|
||||
|
||||
override fun unlockAppIfNeeded() {
|
||||
appLocked = presenter.isAppLocked()
|
||||
if (appLocked) {
|
||||
binding.blurView.setBlurEnabled(true)
|
||||
authenticator.authenticate(getString(commonR.string.biometric_title))
|
||||
} else {
|
||||
binding.blurView.setBlurEnabled(false)
|
||||
}
|
||||
}
|
||||
|
||||
private fun hideSystemUI() {
|
||||
windowInsetsController.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
|
||||
windowInsetsController.hide(WindowInsetsCompat.Type.systemBars())
|
||||
|
|
|
@ -131,8 +131,12 @@ class WebViewPresenterImpl @Inject constructor(
|
|||
}
|
||||
|
||||
override fun switchActiveServer(id: Int) {
|
||||
if (serverId != id && serverId != ServerManager.SERVER_ID_ACTIVE) {
|
||||
setAppActive(false) // 'Lock' old server
|
||||
}
|
||||
setActiveServer(id)
|
||||
onViewReady(null)
|
||||
view.unlockAppIfNeeded()
|
||||
}
|
||||
|
||||
override fun nextServer() = moveToServer(next = true)
|
||||
|
|
Loading…
Reference in a new issue