From 3b70416b66a5a0f558a0bdbff04e5d9e8d98a7f2 Mon Sep 17 00:00:00 2001 From: Josia Pietsch Date: Sat, 24 May 2025 22:51:11 +0200 Subject: [PATCH] implement #181 --- .../launcher/actions/WidgetPanelAction.kt | 12 +- .../jrpie/android/launcher/ui/HomeActivity.kt | 93 ++-------------- .../ui/util/LauncherGestureActivity.kt | 104 ++++++++++++++++++ .../android/launcher/ui/widgets/ClockView.kt | 9 +- .../ui/widgets/WidgetPanelActivity.kt | 27 +++-- .../android/launcher/widgets/ClockWidget.kt | 4 +- 6 files changed, 149 insertions(+), 100 deletions(-) create mode 100644 app/src/main/java/de/jrpie/android/launcher/ui/util/LauncherGestureActivity.kt diff --git a/app/src/main/java/de/jrpie/android/launcher/actions/WidgetPanelAction.kt b/app/src/main/java/de/jrpie/android/launcher/actions/WidgetPanelAction.kt index d7829a6..84c4179 100644 --- a/app/src/main/java/de/jrpie/android/launcher/actions/WidgetPanelAction.kt +++ b/app/src/main/java/de/jrpie/android/launcher/actions/WidgetPanelAction.kt @@ -1,5 +1,6 @@ package de.jrpie.android.launcher.actions +import android.app.Activity import android.content.Context import android.content.Intent import android.graphics.Rect @@ -25,11 +26,18 @@ class WidgetPanelAction(val widgetPanelId: Int) : Action { override fun invoke(context: Context, rect: Rect?): Boolean { - if (WidgetPanel.byId(widgetPanelId) == null) { + if (context is WidgetPanelActivity) { + if (context.widgetPanelId == widgetPanelId) { + context.finish() + return true + } + } + + if (WidgetPanel.byId(this.widgetPanelId) == null) { Toast.makeText(context, R.string.alert_widget_panel_not_found, Toast.LENGTH_LONG).show() } else { context.startActivity(Intent(context, WidgetPanelActivity::class.java).also { - it.putExtra(EXTRA_PANEL_ID, widgetPanelId) + it.putExtra(EXTRA_PANEL_ID, this.widgetPanelId) }) } return true diff --git a/app/src/main/java/de/jrpie/android/launcher/ui/HomeActivity.kt b/app/src/main/java/de/jrpie/android/launcher/ui/HomeActivity.kt index f3cde9a..76bf443 100644 --- a/app/src/main/java/de/jrpie/android/launcher/ui/HomeActivity.kt +++ b/app/src/main/java/de/jrpie/android/launcher/ui/HomeActivity.kt @@ -1,16 +1,9 @@ package de.jrpie.android.launcher.ui -import android.annotation.SuppressLint -import android.app.Activity import android.content.SharedPreferences -import android.content.res.Configuration import android.content.res.Resources -import android.os.Build import android.os.Bundle -import android.view.KeyEvent -import android.view.MotionEvent import android.view.View -import android.window.OnBackInvokedDispatcher import de.jrpie.android.launcher.Application import de.jrpie.android.launcher.actions.Action import de.jrpie.android.launcher.actions.Gesture @@ -19,6 +12,7 @@ import de.jrpie.android.launcher.databinding.ActivityHomeBinding import de.jrpie.android.launcher.openTutorial import de.jrpie.android.launcher.preferences.LauncherPreferences import de.jrpie.android.launcher.ui.tutorial.TutorialActivity +import de.jrpie.android.launcher.ui.util.LauncherGestureActivity /** * [HomeActivity] is the actual application Launcher, @@ -32,10 +26,9 @@ import de.jrpie.android.launcher.ui.tutorial.TutorialActivity * - Setting global variables (preferences etc.) * - Opening the [TutorialActivity] on new installations */ -class HomeActivity : UIObject, Activity() { +class HomeActivity : UIObject, LauncherGestureActivity() { private lateinit var binding: ActivityHomeBinding - private var touchGestureDetector: TouchGestureDetector? = null private var sharedPreferencesListener = SharedPreferences.OnSharedPreferenceChangeListener { _, prefKey -> @@ -54,35 +47,21 @@ class HomeActivity : UIObject, Activity() { } override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) + super.onCreate(savedInstanceState) super.onCreate() - // Initialise layout binding = ActivityHomeBinding.inflate(layoutInflater) setContentView(binding.root) - // Handle back key / gesture on Android 13+, cf. onKeyDown() - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - onBackInvokedDispatcher.registerOnBackInvokedCallback( - OnBackInvokedDispatcher.PRIORITY_OVERLAY - ) { - handleBack() - } - } binding.buttonFallbackSettings.setOnClickListener { LauncherAction.SETTINGS.invoke(this) } } - override fun onConfigurationChanged(newConfig: Configuration) { - super.onConfigurationChanged(newConfig) - touchGestureDetector?.updateScreenSize(windowManager) - } - override fun onStart() { - super.onStart() + super.onStart() super.onStart() // If the tutorial was not finished, start it @@ -133,82 +112,30 @@ class HomeActivity : UIObject, Activity() { override fun onResume() { super.onResume() - - /* This should be initialized in onCreate() - However on some devices there seems to be a bug where the touchGestureDetector - is not working properly after resuming the app. - Reinitializing the touchGestureDetector every time the app is resumed might help to fix that. - (see issue #138) - */ - touchGestureDetector = TouchGestureDetector( - this, 0, 0, - LauncherPreferences.enabled_gestures().edgeSwipeEdgeWidth() / 100f - ).also { - it.updateScreenSize(windowManager) - } - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - binding.root.setOnApplyWindowInsetsListener { _, windowInsets -> - @Suppress("deprecation") // required to support API 29 - val insets = windowInsets.systemGestureInsets - touchGestureDetector?.setSystemGestureInsets(insets) - - windowInsets - } - } updateSettingsFallbackButtonVisibility() binding.homeWidgetContainer.updateWidgets(this@HomeActivity, LauncherPreferences.widgets().widgets() ) - (application as Application).appWidgetHost.startListening() } + override fun onDestroy() { LauncherPreferences.getSharedPreferences() .unregisterOnSharedPreferenceChangeListener(sharedPreferencesListener) super.onDestroy() } - @SuppressLint("GestureBackNavigation") - override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { - when (keyCode) { - KeyEvent.KEYCODE_BACK -> { - // Only used pre Android 13, cf. onBackInvokedDispatcher - handleBack() - } - - KeyEvent.KEYCODE_VOLUME_UP -> { - if (Action.forGesture(Gesture.VOLUME_UP) == LauncherAction.VOLUME_UP) { - // Let the OS handle the key event. This works better with some custom ROMs - // and apps like Samsung Sound Assistant. - return false - } - Gesture.VOLUME_UP(this) - } - - KeyEvent.KEYCODE_VOLUME_DOWN -> { - if (Action.forGesture(Gesture.VOLUME_DOWN) == LauncherAction.VOLUME_DOWN) { - // see above - return false - } - Gesture.VOLUME_DOWN(this) - } - } - return true - } - - override fun onTouchEvent(event: MotionEvent): Boolean { - touchGestureDetector?.onTouchEvent(event) - return true - } - - private fun handleBack() { + override fun handleBack() { Gesture.BACK(this) } + override fun getRootView(): View { + return binding.root + } + override fun isHomeScreen(): Boolean { return true } diff --git a/app/src/main/java/de/jrpie/android/launcher/ui/util/LauncherGestureActivity.kt b/app/src/main/java/de/jrpie/android/launcher/ui/util/LauncherGestureActivity.kt new file mode 100644 index 0000000..0be09f9 --- /dev/null +++ b/app/src/main/java/de/jrpie/android/launcher/ui/util/LauncherGestureActivity.kt @@ -0,0 +1,104 @@ +package de.jrpie.android.launcher.ui.util + +import android.annotation.SuppressLint +import android.app.Activity +import android.content.res.Configuration +import android.os.Build +import android.os.Bundle +import android.view.KeyEvent +import android.view.MotionEvent +import android.view.View +import android.window.OnBackInvokedDispatcher +import de.jrpie.android.launcher.actions.Action +import de.jrpie.android.launcher.actions.Gesture +import de.jrpie.android.launcher.actions.LauncherAction +import de.jrpie.android.launcher.preferences.LauncherPreferences +import de.jrpie.android.launcher.ui.TouchGestureDetector + +/** + * An activity with a [TouchGestureDetector] as well as handling of volume and back keys set up. + */ +abstract class LauncherGestureActivity: Activity() { + protected var touchGestureDetector: TouchGestureDetector? = null + + override fun onTouchEvent(event: MotionEvent): Boolean { + touchGestureDetector?.onTouchEvent(event) + return true + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + // Handle back key / gesture on Android 13+, cf. onKeyDown() + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + onBackInvokedDispatcher.registerOnBackInvokedCallback( + OnBackInvokedDispatcher.PRIORITY_OVERLAY + ) { + handleBack() + } + } + } + + override fun onResume() { + super.onResume() + + /* This should be initialized in onCreate() + However on some devices there seems to be a bug where the touchGestureDetector + is not working properly after resuming the app. + Reinitializing the touchGestureDetector every time the app is resumed might help to fix that. + (see issue #138) + */ + touchGestureDetector = TouchGestureDetector( + this, 0, 0, + LauncherPreferences.enabled_gestures().edgeSwipeEdgeWidth() / 100f + ).also { + it.updateScreenSize(windowManager) + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + getRootView()?.setOnApplyWindowInsetsListener { _, windowInsets -> + @Suppress("deprecation") // required to support API 29 + val insets = windowInsets.systemGestureInsets + touchGestureDetector?.setSystemGestureInsets(insets) + + windowInsets + } + } + } + + @SuppressLint("GestureBackNavigation") + override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { + when (keyCode) { + KeyEvent.KEYCODE_BACK -> { + // Only used pre Android 13, cf. onBackInvokedDispatcher + handleBack() + } + + KeyEvent.KEYCODE_VOLUME_UP -> { + if (Action.forGesture(Gesture.VOLUME_UP) == LauncherAction.VOLUME_UP) { + // Let the OS handle the key event. This works better with some custom ROMs + // and apps like Samsung Sound Assistant. + return false + } + Gesture.VOLUME_UP(this) + } + + KeyEvent.KEYCODE_VOLUME_DOWN -> { + if (Action.forGesture(Gesture.VOLUME_DOWN) == LauncherAction.VOLUME_DOWN) { + // see above + return false + } + Gesture.VOLUME_DOWN(this) + } + } + return true + } + + override fun onConfigurationChanged(newConfig: Configuration) { + super.onConfigurationChanged(newConfig) + touchGestureDetector?.updateScreenSize(windowManager) + } + + protected abstract fun getRootView(): View? + protected abstract fun handleBack() +} \ No newline at end of file diff --git a/app/src/main/java/de/jrpie/android/launcher/ui/widgets/ClockView.kt b/app/src/main/java/de/jrpie/android/launcher/ui/widgets/ClockView.kt index 54d3869..cbe5395 100644 --- a/app/src/main/java/de/jrpie/android/launcher/ui/widgets/ClockView.kt +++ b/app/src/main/java/de/jrpie/android/launcher/ui/widgets/ClockView.kt @@ -8,9 +8,11 @@ import androidx.core.view.isVisible import de.jrpie.android.launcher.actions.Gesture import de.jrpie.android.launcher.databinding.WidgetClockBinding import de.jrpie.android.launcher.preferences.LauncherPreferences +import de.jrpie.android.launcher.widgets.WidgetPanel import java.util.Locale -class ClockView(context: Context, attrs: AttributeSet? = null, val appWidgetId: Int): ConstraintLayout(context, attrs) { +class ClockView(context: Context, attrs: AttributeSet? = null, val appWidgetId: Int, val panelId: Int): ConstraintLayout(context, attrs) { + constructor(context: Context, attrs: AttributeSet?): this(context, attrs, WidgetPanel.HOME.id, -1) val binding: WidgetClockBinding = WidgetClockBinding.inflate(LayoutInflater.from(context), this, true) init { @@ -57,7 +59,7 @@ class ClockView(context: Context, attrs: AttributeSet? = null, val appWidgetId: binding.clockUpperView.format12Hour = upperFormat } - fun setOnClicks() { + private fun setOnClicks() { binding.clockUpperView.setOnClickListener { if (LauncherPreferences.clock().flipDateTime()) { Gesture.TIME(context) @@ -74,7 +76,4 @@ class ClockView(context: Context, attrs: AttributeSet? = null, val appWidgetId: } } } - - - } \ No newline at end of file diff --git a/app/src/main/java/de/jrpie/android/launcher/ui/widgets/WidgetPanelActivity.kt b/app/src/main/java/de/jrpie/android/launcher/ui/widgets/WidgetPanelActivity.kt index 3c884db..7d51b08 100644 --- a/app/src/main/java/de/jrpie/android/launcher/ui/widgets/WidgetPanelActivity.kt +++ b/app/src/main/java/de/jrpie/android/launcher/ui/widgets/WidgetPanelActivity.kt @@ -1,27 +1,31 @@ package de.jrpie.android.launcher.ui.widgets -import android.app.Activity import android.content.res.Resources import android.os.Bundle +import android.view.View import androidx.core.view.ViewCompat import de.jrpie.android.launcher.Application import de.jrpie.android.launcher.R import de.jrpie.android.launcher.databinding.ActivityWidgetPanelBinding import de.jrpie.android.launcher.preferences.LauncherPreferences import de.jrpie.android.launcher.ui.UIObject +import de.jrpie.android.launcher.ui.util.LauncherGestureActivity import de.jrpie.android.launcher.ui.widgets.manage.EXTRA_PANEL_ID import de.jrpie.android.launcher.widgets.WidgetPanel -class WidgetPanelActivity : Activity(), UIObject { - lateinit var binding: ActivityWidgetPanelBinding - private var widgetPanelId: Int = WidgetPanel.HOME.id +class WidgetPanelActivity : LauncherGestureActivity(), UIObject { + var binding: ActivityWidgetPanelBinding? = null + + var widgetPanelId: Int = WidgetPanel.HOME.id + override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) + super.onCreate(savedInstanceState) super.onCreate() - widgetPanelId = intent.getIntExtra(EXTRA_PANEL_ID, WidgetPanel.HOME.id) val binding = ActivityWidgetPanelBinding.inflate(layoutInflater) setContentView(binding.root) + widgetPanelId = intent.getIntExtra(EXTRA_PANEL_ID, WidgetPanel.HOME.id) + // The widget container should extend below the status and navigation bars, // so let's set an empty WindowInsetsListener to prevent it from being moved. ViewCompat.setOnApplyWindowInsetsListener(binding.root) { _, windowInsets -> @@ -56,9 +60,8 @@ class WidgetPanelActivity : Activity(), UIObject { } override fun onStart() { - super.onStart() + super.onStart() super.onStart() - } override fun onPause() { @@ -76,6 +79,14 @@ class WidgetPanelActivity : Activity(), UIObject { (application as Application).appWidgetHost.startListening() } + override fun getRootView(): View? { + return binding?.root + } + + override fun handleBack() { + finish() + } + override fun isHomeScreen(): Boolean { return true } diff --git a/app/src/main/java/de/jrpie/android/launcher/widgets/ClockWidget.kt b/app/src/main/java/de/jrpie/android/launcher/widgets/ClockWidget.kt index f864ee8..29d9308 100644 --- a/app/src/main/java/de/jrpie/android/launcher/widgets/ClockWidget.kt +++ b/app/src/main/java/de/jrpie/android/launcher/widgets/ClockWidget.kt @@ -18,8 +18,8 @@ class ClockWidget( override var allowInteraction: Boolean = true ) : Widget() { - override fun createView(activity: Activity): View? { - return ClockView(activity, null, id) + override fun createView(activity: Activity): View { + return ClockView(activity, null, id, panelId) } override fun findView(views: Sequence): ClockView? {