mirror of
https://github.com/jrpie/Launcher.git
synced 2025-04-11 23:04:32 +02:00
lint
This commit is contained in:
parent
e250a58ef4
commit
077ee4381a
12 changed files with 75 additions and 36 deletions
|
@ -10,6 +10,8 @@ import android.content.pm.ShortcutInfo
|
||||||
import android.os.AsyncTask
|
import android.os.AsyncTask
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Build.VERSION_CODES
|
import android.os.Build.VERSION_CODES
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.Looper
|
||||||
import android.os.UserHandle
|
import android.os.UserHandle
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
@ -108,12 +110,10 @@ class Application : android.app.Application() {
|
||||||
// Try to restore old preferences
|
// Try to restore old preferences
|
||||||
migratePreferencesToNewVersion(this)
|
migratePreferencesToNewVersion(this)
|
||||||
|
|
||||||
// First time opening the app: set defaults and start tutorial
|
// First time opening the app: set defaults
|
||||||
|
// The tutorial is started from HomeActivity#onStart, as starting it here is blocked by android
|
||||||
if (!LauncherPreferences.internal().started()) {
|
if (!LauncherPreferences.internal().started()) {
|
||||||
resetPreferences(this)
|
resetPreferences(this)
|
||||||
|
|
||||||
LauncherPreferences.internal().started(true)
|
|
||||||
openTutorial(this)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -134,7 +134,8 @@ class Application : android.app.Application() {
|
||||||
it.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)
|
it.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ContextCompat.registerReceiver(this, profileAvailabilityBroadcastReceiver, filter,
|
ContextCompat.registerReceiver(
|
||||||
|
this, profileAvailabilityBroadcastReceiver, filter,
|
||||||
ContextCompat.RECEIVER_EXPORTED
|
ContextCompat.RECEIVER_EXPORTED
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -135,9 +135,7 @@ fun openInBrowser(url: String, context: Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun openTutorial(context: Context) {
|
fun openTutorial(context: Context) {
|
||||||
context.startActivity(Intent(context, TutorialActivity::class.java).apply {
|
context.startActivity(Intent(context, TutorialActivity::class.java))
|
||||||
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -21,8 +21,10 @@ import eu.jonahbauer.android.preference.annotations.Preferences;
|
||||||
r = R.class,
|
r = R.class,
|
||||||
value = {
|
value = {
|
||||||
@PreferenceGroup(name = "internal", prefix = "settings_internal_", suffix = "_key", value = {
|
@PreferenceGroup(name = "internal", prefix = "settings_internal_", suffix = "_key", value = {
|
||||||
|
// set after the user finished the tutorial
|
||||||
@Preference(name = "started", type = boolean.class, defaultValue = "false"),
|
@Preference(name = "started", type = boolean.class, defaultValue = "false"),
|
||||||
@Preference(name = "started_time", type = long.class),
|
@Preference(name = "started_time", type = long.class),
|
||||||
|
// see PREFERENCE_VERSION in de.jrpie.android.launcher.preferences.Preferences.kt
|
||||||
@Preference(name = "version_code", type = int.class, defaultValue = "-1"),
|
@Preference(name = "version_code", type = int.class, defaultValue = "-1"),
|
||||||
}),
|
}),
|
||||||
@PreferenceGroup(name = "apps", prefix = "settings_apps_", suffix = "_key", value = {
|
@PreferenceGroup(name = "apps", prefix = "settings_apps_", suffix = "_key", value = {
|
||||||
|
|
|
@ -100,7 +100,7 @@ private fun migrateAppInfoStringMap(key: String) {
|
||||||
}
|
}
|
||||||
}?.toMap(HashMap())
|
}?.toMap(HashMap())
|
||||||
)?.let {
|
)?.let {
|
||||||
preferences.edit().putStringSet(key, it as Set<String>).apply()
|
preferences.edit().putStringSet(key, it).apply()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ import de.jrpie.android.launcher.preferences.serialization.SetAbstractAppInfoPre
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import java.util.HashSet
|
import java.util.HashSet
|
||||||
|
import androidx.core.content.edit
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Migrate preferences from version 3 (used until version 0.0.23) to the current format
|
* Migrate preferences from version 3 (used until version 0.0.23) to the current format
|
||||||
|
@ -42,6 +43,7 @@ private fun migrateSetAppInfo(key: String, preferences: SharedPreferences, edito
|
||||||
deserializeSet(preferences.getStringSet(key, null))?.let {
|
deserializeSet(preferences.getStringSet(key, null))?.let {
|
||||||
set.addAll(it)
|
set.addAll(it)
|
||||||
}
|
}
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
editor.putStringSet(
|
editor.putStringSet(
|
||||||
key,
|
key,
|
||||||
serializer.serialize(set as java.util.Set<AbstractAppInfo>) as Set<String>?
|
serializer.serialize(set as java.util.Set<AbstractAppInfo>) as Set<String>?
|
||||||
|
@ -60,6 +62,7 @@ private fun migrateMapAppInfoString(key: String, preferences: SharedPreferences,
|
||||||
deserializeMap(preferences.getStringSet(key, null))?.let {
|
deserializeMap(preferences.getStringSet(key, null))?.let {
|
||||||
map.putAll(it)
|
map.putAll(it)
|
||||||
}
|
}
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
editor.putStringSet(key, serializer.serialize(map) as Set<String>?)
|
editor.putStringSet(key, serializer.serialize(map) as Set<String>?)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
|
@ -72,14 +75,11 @@ fun migratePreferencesFromVersion3() {
|
||||||
assert(LauncherPreferences.internal().versionCode() == 3)
|
assert(LauncherPreferences.internal().versionCode() == 3)
|
||||||
|
|
||||||
val preferences = LauncherPreferences.getSharedPreferences()
|
val preferences = LauncherPreferences.getSharedPreferences()
|
||||||
val editor = preferences.edit()
|
preferences.edit {
|
||||||
migrateSetAppInfo(LauncherPreferences.apps().keys().favorites(), preferences, editor)
|
migrateSetAppInfo(LauncherPreferences.apps().keys().favorites(), preferences, this)
|
||||||
migrateSetAppInfo(LauncherPreferences.apps().keys().hidden(), preferences, editor)
|
migrateSetAppInfo(LauncherPreferences.apps().keys().hidden(), preferences, this)
|
||||||
migrateMapAppInfoString(LauncherPreferences.apps().keys().customNames(), preferences, editor)
|
migrateMapAppInfoString(LauncherPreferences.apps().keys().customNames(), preferences, this)
|
||||||
|
}
|
||||||
editor.apply()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
LauncherPreferences.internal().versionCode(4)
|
LauncherPreferences.internal().versionCode(4)
|
||||||
}
|
}
|
|
@ -9,9 +9,6 @@ import android.util.DisplayMetrics
|
||||||
import android.view.KeyEvent
|
import android.view.KeyEvent
|
||||||
import android.view.MotionEvent
|
import android.view.MotionEvent
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.Window
|
|
||||||
import android.view.WindowInsets
|
|
||||||
import android.view.WindowInsetsController
|
|
||||||
import android.window.OnBackInvokedDispatcher
|
import android.window.OnBackInvokedDispatcher
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
|
@ -20,6 +17,7 @@ import de.jrpie.android.launcher.actions.Action
|
||||||
import de.jrpie.android.launcher.actions.Gesture
|
import de.jrpie.android.launcher.actions.Gesture
|
||||||
import de.jrpie.android.launcher.actions.LauncherAction
|
import de.jrpie.android.launcher.actions.LauncherAction
|
||||||
import de.jrpie.android.launcher.databinding.HomeBinding
|
import de.jrpie.android.launcher.databinding.HomeBinding
|
||||||
|
import de.jrpie.android.launcher.openTutorial
|
||||||
import de.jrpie.android.launcher.preferences.LauncherPreferences
|
import de.jrpie.android.launcher.preferences.LauncherPreferences
|
||||||
import de.jrpie.android.launcher.ui.tutorial.TutorialActivity
|
import de.jrpie.android.launcher.ui.tutorial.TutorialActivity
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
@ -58,7 +56,6 @@ class HomeActivity : UIObject, AppCompatActivity() {
|
||||||
super<AppCompatActivity>.onCreate(savedInstanceState)
|
super<AppCompatActivity>.onCreate(savedInstanceState)
|
||||||
super<UIObject>.onCreate()
|
super<UIObject>.onCreate()
|
||||||
|
|
||||||
|
|
||||||
val displayMetrics = DisplayMetrics()
|
val displayMetrics = DisplayMetrics()
|
||||||
windowManager.defaultDisplay.getMetrics(displayMetrics)
|
windowManager.defaultDisplay.getMetrics(displayMetrics)
|
||||||
|
|
||||||
|
@ -88,8 +85,6 @@ class HomeActivity : UIObject, AppCompatActivity() {
|
||||||
binding.buttonFallbackSettings.setOnClickListener {
|
binding.buttonFallbackSettings.setOnClickListener {
|
||||||
LauncherAction.SETTINGS.invoke(this)
|
LauncherAction.SETTINGS.invoke(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStart() {
|
override fun onStart() {
|
||||||
|
@ -97,6 +92,11 @@ class HomeActivity : UIObject, AppCompatActivity() {
|
||||||
|
|
||||||
super<UIObject>.onStart()
|
super<UIObject>.onStart()
|
||||||
|
|
||||||
|
// If the tutorial was not finished, start it
|
||||||
|
if (!LauncherPreferences.internal().started()) {
|
||||||
|
openTutorial(this)
|
||||||
|
}
|
||||||
|
|
||||||
LauncherPreferences.getSharedPreferences()
|
LauncherPreferences.getSharedPreferences()
|
||||||
.registerOnSharedPreferenceChangeListener(sharedPreferencesListener)
|
.registerOnSharedPreferenceChangeListener(sharedPreferencesListener)
|
||||||
|
|
||||||
|
@ -220,7 +220,8 @@ class HomeActivity : UIObject, AppCompatActivity() {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onTouchEvent(event: MotionEvent): Boolean {
|
override fun onTouchEvent(event: MotionEvent): Boolean {
|
||||||
return touchGestureDetector.onTouchEvent(event) || super.onTouchEvent(event)
|
touchGestureDetector.onTouchEvent(event)
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setOnClicks() {
|
override fun setOnClicks() {
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package de.jrpie.android.launcher.ui
|
package de.jrpie.android.launcher.ui
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.Looper
|
||||||
import android.view.MotionEvent
|
import android.view.MotionEvent
|
||||||
import android.view.ViewConfiguration
|
import android.view.ViewConfiguration
|
||||||
import de.jrpie.android.launcher.actions.Gesture
|
import de.jrpie.android.launcher.actions.Gesture
|
||||||
|
@ -27,6 +29,8 @@ class TouchGestureDetector(
|
||||||
|
|
||||||
private val MIN_TRIANGLE_HEIGHT = 250
|
private val MIN_TRIANGLE_HEIGHT = 250
|
||||||
|
|
||||||
|
private val longPressHandler = Handler(Looper.getMainLooper())
|
||||||
|
|
||||||
|
|
||||||
data class Vector(val x: Float, val y: Float) {
|
data class Vector(val x: Float, val y: Float) {
|
||||||
fun absSquared(): Float {
|
fun absSquared(): Float {
|
||||||
|
@ -83,16 +87,28 @@ class TouchGestureDetector(
|
||||||
}
|
}
|
||||||
|
|
||||||
private var paths = HashMap<Int, PointerPath>()
|
private var paths = HashMap<Int, PointerPath>()
|
||||||
|
private var gestureIsLongClick = false
|
||||||
|
|
||||||
private var lastTappedTime = 0L
|
private var lastTappedTime = 0L
|
||||||
private var lastTappedLocation: Vector? = null
|
private var lastTappedLocation: Vector? = null
|
||||||
|
|
||||||
fun onTouchEvent(event: MotionEvent): Boolean {
|
fun onTouchEvent(event: MotionEvent) {
|
||||||
val pointerIdToIndex =
|
val pointerIdToIndex =
|
||||||
(0..<event.pointerCount).associateBy { event.getPointerId(it) }
|
(0..<event.pointerCount).associateBy { event.getPointerId(it) }
|
||||||
|
|
||||||
if (event.actionMasked == MotionEvent.ACTION_DOWN) {
|
if (event.actionMasked == MotionEvent.ACTION_DOWN) {
|
||||||
paths = HashMap()
|
synchronized(this@TouchGestureDetector) {
|
||||||
|
paths = HashMap()
|
||||||
|
gestureIsLongClick = false
|
||||||
|
}
|
||||||
|
longPressHandler.postDelayed({
|
||||||
|
synchronized(this@TouchGestureDetector) {
|
||||||
|
if (paths.entries.size == 1 && paths.entries.firstOrNull()?.value?.isTap() == true) {
|
||||||
|
gestureIsLongClick = true
|
||||||
|
Gesture.LONG_CLICK.invoke(context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, LONG_PRESS_TIMEOUT.toLong())
|
||||||
}
|
}
|
||||||
|
|
||||||
// add new pointers
|
// add new pointers
|
||||||
|
@ -122,9 +138,17 @@ class TouchGestureDetector(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.actionMasked == MotionEvent.ACTION_UP) {
|
if (event.actionMasked == MotionEvent.ACTION_UP) {
|
||||||
|
synchronized(this@TouchGestureDetector) {
|
||||||
|
// if the long press handler is still running, kill it
|
||||||
|
longPressHandler.removeCallbacksAndMessages(null)
|
||||||
|
// if the gesture was already detected as a long click, there is nothing to do
|
||||||
|
if (gestureIsLongClick) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
classifyPaths(paths, event.downTime, event.eventTime)
|
classifyPaths(paths, event.downTime, event.eventTime)
|
||||||
}
|
}
|
||||||
return true
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getGestureForDirection(direction: Vector): Gesture? {
|
private fun getGestureForDirection(direction: Vector): Gesture? {
|
||||||
|
@ -171,10 +195,6 @@ class TouchGestureDetector(
|
||||||
lastTappedTime = timeEnd
|
lastTappedTime = timeEnd
|
||||||
lastTappedLocation = mainPointerPath.last
|
lastTappedLocation = mainPointerPath.last
|
||||||
}
|
}
|
||||||
} else if (duration > LONG_PRESS_TIMEOUT) {
|
|
||||||
// TODO: Don't wait until the finger is lifted.
|
|
||||||
// Instead set a timer to start long click as soon as LONG_PRESS_TIMEOUT is reached
|
|
||||||
Gesture.LONG_CLICK.invoke(context)
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// detect swipes
|
// detect swipes
|
||||||
|
|
|
@ -67,7 +67,7 @@ class AppsRecyclerAdapter(
|
||||||
override fun onClick(v: View) {
|
override fun onClick(v: View) {
|
||||||
val rect = Rect()
|
val rect = Rect()
|
||||||
img.getGlobalVisibleRect(rect)
|
img.getGlobalVisibleRect(rect)
|
||||||
selectItem(adapterPosition, rect)
|
selectItem(bindingAdapterPosition, rect)
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
|
|
@ -22,6 +22,7 @@ import de.jrpie.android.launcher.apps.DetailedAppInfo
|
||||||
import de.jrpie.android.launcher.apps.PinnedShortcutInfo
|
import de.jrpie.android.launcher.apps.PinnedShortcutInfo
|
||||||
import de.jrpie.android.launcher.getUserFromId
|
import de.jrpie.android.launcher.getUserFromId
|
||||||
import de.jrpie.android.launcher.preferences.LauncherPreferences
|
import de.jrpie.android.launcher.preferences.LauncherPreferences
|
||||||
|
import androidx.core.net.toUri
|
||||||
|
|
||||||
private const val LOG_TAG = "AppContextMenu"
|
private const val LOG_TAG = "AppContextMenu"
|
||||||
|
|
||||||
|
@ -44,7 +45,7 @@ fun AbstractAppInfo.uninstall(activity: Activity) {
|
||||||
Log.i(LOG_TAG, "uninstalling $this")
|
Log.i(LOG_TAG, "uninstalling $this")
|
||||||
|
|
||||||
val intent = Intent(Intent.ACTION_UNINSTALL_PACKAGE)
|
val intent = Intent(Intent.ACTION_UNINSTALL_PACKAGE)
|
||||||
intent.data = Uri.parse("package:$packageName")
|
intent.data = "package:$packageName".toUri()
|
||||||
getUserFromId(userId, activity).let { user ->
|
getUserFromId(userId, activity).let { user ->
|
||||||
intent.putExtra(Intent.EXTRA_USER, user)
|
intent.putExtra(Intent.EXTRA_USER, user)
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ class OtherRecyclerAdapter(val activity: Activity) :
|
||||||
|
|
||||||
|
|
||||||
override fun onClick(v: View) {
|
override fun onClick(v: View) {
|
||||||
val pos = adapterPosition
|
val pos = bindingAdapterPosition
|
||||||
val content = othersList[pos]
|
val content = othersList[pos]
|
||||||
|
|
||||||
forGesture?.let { returnChoiceIntent(it, content) }
|
forGesture?.let { returnChoiceIntent(it, content) }
|
||||||
|
|
|
@ -16,6 +16,7 @@ import de.jrpie.android.launcher.copyToClipboard
|
||||||
import de.jrpie.android.launcher.databinding.SettingsMetaBinding
|
import de.jrpie.android.launcher.databinding.SettingsMetaBinding
|
||||||
import de.jrpie.android.launcher.getDeviceInfo
|
import de.jrpie.android.launcher.getDeviceInfo
|
||||||
import de.jrpie.android.launcher.openInBrowser
|
import de.jrpie.android.launcher.openInBrowser
|
||||||
|
import de.jrpie.android.launcher.openTutorial
|
||||||
import de.jrpie.android.launcher.preferences.resetPreferences
|
import de.jrpie.android.launcher.preferences.resetPreferences
|
||||||
import de.jrpie.android.launcher.ui.LegalInfoActivity
|
import de.jrpie.android.launcher.ui.LegalInfoActivity
|
||||||
import de.jrpie.android.launcher.ui.UIObject
|
import de.jrpie.android.launcher.ui.UIObject
|
||||||
|
@ -48,7 +49,7 @@ class SettingsFragmentMeta : Fragment(), UIObject {
|
||||||
override fun setOnClicks() {
|
override fun setOnClicks() {
|
||||||
|
|
||||||
binding.settingsMetaButtonViewTutorial.setOnClickListener {
|
binding.settingsMetaButtonViewTutorial.setOnClickListener {
|
||||||
startActivity(Intent(this.context, TutorialActivity::class.java))
|
openTutorial(requireContext())
|
||||||
}
|
}
|
||||||
|
|
||||||
// prompting for settings-reset confirmation
|
// prompting for settings-reset confirmation
|
||||||
|
|
|
@ -2,7 +2,9 @@ package de.jrpie.android.launcher.ui.tutorial
|
||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.window.OnBackInvokedDispatcher
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.FragmentManager
|
import androidx.fragment.app.FragmentManager
|
||||||
|
@ -33,6 +35,19 @@ class TutorialActivity : AppCompatActivity(), UIObject {
|
||||||
super<AppCompatActivity>.onCreate(savedInstanceState)
|
super<AppCompatActivity>.onCreate(savedInstanceState)
|
||||||
super<UIObject>.onCreate()
|
super<UIObject>.onCreate()
|
||||||
|
|
||||||
|
// Handle back key / gesture on Android 13+
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
|
onBackInvokedDispatcher.registerOnBackInvokedCallback(
|
||||||
|
OnBackInvokedDispatcher.PRIORITY_OVERLAY
|
||||||
|
) {
|
||||||
|
// prevent going back when the tutorial is shown for the first time
|
||||||
|
if (!LauncherPreferences.internal().started()) {
|
||||||
|
return@registerOnBackInvokedCallback
|
||||||
|
}
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Initialise layout
|
// Initialise layout
|
||||||
setContentView(R.layout.tutorial)
|
setContentView(R.layout.tutorial)
|
||||||
|
|
||||||
|
@ -60,7 +75,7 @@ class TutorialActivity : AppCompatActivity(), UIObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default: prevent going back, allow if viewed again later
|
// prevent going back when the tutorial is shown for the first time
|
||||||
override fun onBackPressed() {
|
override fun onBackPressed() {
|
||||||
if (LauncherPreferences.internal().started())
|
if (LauncherPreferences.internal().started())
|
||||||
super.onBackPressed()
|
super.onBackPressed()
|
||||||
|
|
Loading…
Add table
Reference in a new issue