From 088414798efa051ec6351f78b66d6f31f45ae2fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Tue, 29 Oct 2019 17:53:48 +0100 Subject: [PATCH] Add On-Screen Controls Toggle to Android --- .../com/metallic/chiaki/common/Preferences.kt | 5 ++ .../metallic/chiaki/stream/StreamActivity.kt | 73 +++++++++++++++++-- .../metallic/chiaki/stream/StreamViewModel.kt | 14 +++- .../touchcontrols/TouchControlsFragment.kt | 9 ++- .../src/main/res/layout/activity_stream.xml | 46 ++++++++++-- .../src/main/res/layout/fragment_controls.xml | 3 +- android/app/src/main/res/values/colors.xml | 1 + android/app/src/main/res/values/strings.xml | 1 + android/app/src/main/res/values/styles.xml | 2 + 9 files changed, 137 insertions(+), 17 deletions(-) diff --git a/android/app/src/main/java/com/metallic/chiaki/common/Preferences.kt b/android/app/src/main/java/com/metallic/chiaki/common/Preferences.kt index 0bbcfe6..cd30456 100644 --- a/android/app/src/main/java/com/metallic/chiaki/common/Preferences.kt +++ b/android/app/src/main/java/com/metallic/chiaki/common/Preferences.kt @@ -69,6 +69,11 @@ class Preferences(context: Context) get() = sharedPreferences.getBoolean(discoveryEnabledKey, true) set(value) { sharedPreferences.edit().putBoolean(discoveryEnabledKey, value).apply() } + val onScreenControlsEnabledKey get() = resources.getString(R.string.preferences_on_screen_controls_enabled_key) + var onScreenControlsEnabled + get() = sharedPreferences.getBoolean(onScreenControlsEnabledKey, true) + set(value) { sharedPreferences.edit().putBoolean(onScreenControlsEnabledKey, value).apply() } + val logVerboseKey get() = resources.getString(R.string.preferences_log_verbose_key) var logVerbose get() = sharedPreferences.getBoolean(logVerboseKey, false) diff --git a/android/app/src/main/java/com/metallic/chiaki/stream/StreamActivity.kt b/android/app/src/main/java/com/metallic/chiaki/stream/StreamActivity.kt index 8d25c38..cbd946b 100644 --- a/android/app/src/main/java/com/metallic/chiaki/stream/StreamActivity.kt +++ b/android/app/src/main/java/com/metallic/chiaki/stream/StreamActivity.kt @@ -17,22 +17,30 @@ package com.metallic.chiaki.stream +import android.animation.Animator +import android.animation.AnimatorListenerAdapter import android.app.AlertDialog import android.app.Dialog import android.content.DialogInterface import android.graphics.Matrix import android.os.Bundle +import android.os.Handler import android.speech.tts.TextToSpeech +import android.text.method.Touch import android.util.Log import android.view.KeyEvent import android.view.View import android.widget.EditText import androidx.appcompat.app.AppCompatActivity +import androidx.core.view.isGone +import androidx.core.view.isVisible import androidx.fragment.app.Fragment import androidx.lifecycle.* import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.metallic.chiaki.* import com.metallic.chiaki.R +import com.metallic.chiaki.common.Preferences +import com.metallic.chiaki.common.ext.viewModelFactory import com.metallic.chiaki.lib.ConnectInfo import com.metallic.chiaki.lib.LoginPinRequestEvent import com.metallic.chiaki.lib.QuitReason @@ -44,20 +52,22 @@ private object StreamQuitDialog: DialogContents() private object CreateErrorDialog: DialogContents() private object PinRequestDialog: DialogContents() -class StreamActivity : AppCompatActivity() +class StreamActivity : AppCompatActivity(), View.OnSystemUiVisibilityChangeListener { companion object { const val EXTRA_CONNECT_INFO = "connect_info" + private const val HIDE_UI_TIMEOUT_MS = 2000L } private lateinit var viewModel: StreamViewModel + private val uiVisibilityHandler = Handler() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - viewModel = ViewModelProviders.of(this)[StreamViewModel::class.java] + viewModel = ViewModelProviders.of(this, viewModelFactory { StreamViewModel(Preferences(this)) })[StreamViewModel::class.java] if(!viewModel.isInitialized) { val connectInfo = intent.getParcelableExtra(EXTRA_CONNECT_INFO) @@ -70,11 +80,19 @@ class StreamActivity : AppCompatActivity() } setContentView(R.layout.activity_stream) + window.decorView.setOnSystemUiVisibilityChangeListener(this) + + viewModel.onScreenControlsEnabled.observe(this, Observer { + if(onScreenControlsSwitch.isChecked != it) + onScreenControlsSwitch.isChecked = it + }) + onScreenControlsSwitch.setOnCheckedChangeListener { _, isChecked -> + viewModel.setOnScreenControlsEnabled(isChecked) + showOverlay() + } viewModel.session.attachToTextureView(textureView) - viewModel.session.state.observe(this, Observer { this.stateChanged(it) }) - textureView.addOnLayoutChangeListener { _, _, _, _, _, _, _, _, _ -> adjustTextureViewAspect() } @@ -83,7 +101,11 @@ class StreamActivity : AppCompatActivity() override fun onAttachFragment(fragment: Fragment) { super.onAttachFragment(fragment) - (fragment as? TouchControlsFragment)?.controllerStateCallback = viewModel.session::updateTouchControllerState + if(fragment is TouchControlsFragment) + { + fragment.controllerStateCallback = viewModel.session::updateTouchControllerState + fragment.onScreenControlsEnabled = viewModel.onScreenControlsEnabled + } } override fun onResume() @@ -105,6 +127,45 @@ class StreamActivity : AppCompatActivity() viewModel.session.resume() } + private val hideSystemUIRunnable = Runnable { hideSystemUI() } + + override fun onSystemUiVisibilityChange(visibility: Int) + { + if(visibility and View.SYSTEM_UI_FLAG_FULLSCREEN == 0) + showOverlay() + else + hideOverlay() + } + + private fun showOverlay() + { + overlay.isVisible = true + overlay.animate() + .alpha(1.0f) + .setListener(object: AnimatorListenerAdapter() + { + override fun onAnimationEnd(animation: Animator?) + { + overlay.alpha = 1.0f + } + }) + uiVisibilityHandler.removeCallbacks(hideSystemUIRunnable) + uiVisibilityHandler.postDelayed(hideSystemUIRunnable, HIDE_UI_TIMEOUT_MS) + } + + private fun hideOverlay() + { + overlay.animate() + .alpha(0.0f) + .setListener(object: AnimatorListenerAdapter() + { + override fun onAnimationEnd(animation: Animator?) + { + overlay.isGone = true + } + }) + } + override fun onWindowFocusChanged(hasFocus: Boolean) { super.onWindowFocusChanged(hasFocus) @@ -114,7 +175,7 @@ class StreamActivity : AppCompatActivity() private fun hideSystemUI() { - window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY + window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_IMMERSIVE or View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN diff --git a/android/app/src/main/java/com/metallic/chiaki/stream/StreamViewModel.kt b/android/app/src/main/java/com/metallic/chiaki/stream/StreamViewModel.kt index aa0300d..205f31a 100644 --- a/android/app/src/main/java/com/metallic/chiaki/stream/StreamViewModel.kt +++ b/android/app/src/main/java/com/metallic/chiaki/stream/StreamViewModel.kt @@ -17,17 +17,23 @@ package com.metallic.chiaki.stream +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import com.metallic.chiaki.StreamSession +import com.metallic.chiaki.common.Preferences import com.metallic.chiaki.lib.* -class StreamViewModel: ViewModel() +class StreamViewModel(val preferences: Preferences): ViewModel() { private var connectInfo: ConnectInfo? = null private var _session: StreamSession? = null val session: StreamSession get() = _session ?: throw UninitializedPropertyAccessException("StreamViewModel not initialized") val isInitialized get() = connectInfo != null + private var _onScreenControlsEnabled = MutableLiveData(preferences.onScreenControlsEnabled) + val onScreenControlsEnabled: LiveData get() = _onScreenControlsEnabled + fun init(connectInfo: ConnectInfo) { if(isInitialized) @@ -40,4 +46,10 @@ class StreamViewModel: ViewModel() super.onCleared() _session?.shutdown() } + + fun setOnScreenControlsEnabled(enabled: Boolean) + { + preferences.onScreenControlsEnabled = enabled + _onScreenControlsEnabled.value = enabled + } } \ No newline at end of file diff --git a/android/app/src/main/java/com/metallic/chiaki/touchcontrols/TouchControlsFragment.kt b/android/app/src/main/java/com/metallic/chiaki/touchcontrols/TouchControlsFragment.kt index 30ea9cc..04e0394 100644 --- a/android/app/src/main/java/com/metallic/chiaki/touchcontrols/TouchControlsFragment.kt +++ b/android/app/src/main/java/com/metallic/chiaki/touchcontrols/TouchControlsFragment.kt @@ -23,13 +23,15 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment +import androidx.lifecycle.LiveData +import androidx.lifecycle.Observer import com.metallic.chiaki.R import com.metallic.chiaki.lib.ControllerState import kotlinx.android.synthetic.main.fragment_controls.* class TouchControlsFragment : Fragment() { - var controllerState = ControllerState() + private var controllerState = ControllerState() private set(value) { val diff = field != value @@ -39,6 +41,7 @@ class TouchControlsFragment : Fragment() } var controllerStateCallback: ((ControllerState) -> Unit)? = null + var onScreenControlsEnabled: LiveData? = null override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View = inflater.inflate(R.layout.fragment_controls, container, false) @@ -74,6 +77,10 @@ class TouchControlsFragment : Fragment() rightX = quantizeStick(it.x) rightY = quantizeStick(it.y) }} + + onScreenControlsEnabled?.observe(this, Observer { + view.visibility = if(it) View.VISIBLE else View.GONE + }) } private fun dpadStateChanged(direction: DPadView.Direction?) diff --git a/android/app/src/main/res/layout/activity_stream.xml b/android/app/src/main/res/layout/activity_stream.xml index 69d5e99..27a32d0 100644 --- a/android/app/src/main/res/layout/activity_stream.xml +++ b/android/app/src/main/res/layout/activity_stream.xml @@ -1,9 +1,9 @@ - + android:layout_gravity="center"/> + android:layout_height="match_parent"/> - \ No newline at end of file + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/layout/fragment_controls.xml b/android/app/src/main/res/layout/fragment_controls.xml index a44931f..a2c24df 100644 --- a/android/app/src/main/res/layout/fragment_controls.xml +++ b/android/app/src/main/res/layout/fragment_controls.xml @@ -1,5 +1,6 @@ -@android:color/white @android:color/black + #77000000 #fafafa #333333 diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml index e78c484..8d8c1f9 100644 --- a/android/app/src/main/res/values/strings.xml +++ b/android/app/src/main/res/values/strings.xml @@ -66,6 +66,7 @@ discovery_enabled + on_screen_controls_enabled log_verbose stream_resolution 360p diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml index 8c9a9ec..4eae563 100644 --- a/android/app/src/main/res/values/styles.xml +++ b/android/app/src/main/res/values/styles.xml @@ -109,5 +109,7 @@ @color/accent @style/AppTheme.AlertDialog @color/stream_background + true + true